From Gossip@caterpillar

Acegi Gossip: 第一個Acegi 程式 - 保護對方法的呼叫





Acegi是專為 Spring 設計的安全框架,藉由Spring所提供的AOP功能,可以使用org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor來對方法呼叫進行攔截,對方法的呼叫設定權限保護。

舉個實際的例子來說,假設您設計了以下的介面與方法:
package onlyfun.caterpillar;

public interface ISome {
public void doNormal();
public void doSupervisor();
}

package onlyfun.caterpillar;

public class Some implements ISome {
public void doNormal() {
System.out.println("do normal...");
}

public void doSupervisor() {
System.out.println("do supervisor...");
}
}

假設某個請求下,會對Some的實例之方法進行呼叫,例如某個Servlet:
package onlyfun.caterpillar;

import java.io.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class SomeServlet extends HttpServlet {

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");

ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
request.getSession().getServletContext());
ISome some = (ISome) ctx.getBean("some");
some.doNormal();
some.doSupervisor();

PrintWriter out = response.getWriter();
out.print("process successfully...");
out.close();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

public String getServletInfo() {
return "Short description";
}
}

在web.xml中增加SomeServlet的定義:
    <servlet>
        <servlet-name>SomeServlet</servlet-name>
        <servlet-class>onlyfun.caterpillar.SomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SomeServlet</servlet-name>
        <url-pattern>/SomeServlet</url-pattern>
    </servlet-mapping>

在不設限的情況下,請求SomeServlet,會呼叫Some實例的doNormal()方法與doSecurity()方法,現在假設您想讓 doSecurity()只讓ROLE_SUPERVISOR的使用者來呼叫,則您可以在acegi-config.xml中加入:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
...

<bean id="some" class="onlyfun.caterpillar.Some"/>

<bean id="methodSecurityInterceptor"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<value>onlyfun.caterpillar.ISome.doSupervisor=ROLE_SUPERVISOR</value>
</property>
</bean>

<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>some</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>methodSecurityInterceptor</value>
</list>
</property>
</bean>
</beans>

完成以下設定,如果再次請求SomeServlet,可以在控制台中看到doNormal()執行完成,但doSecurity()必須是 ROLE_SUPERVISOR才可以存取,因此您會被送往acegilogin.jsp進行登入,如果登入正確,就會執行doSecurity(),如 果登入為非ROLE_SUPERVISOR,則會發生授權失敗的例外。