Struts2+Spring+Acegi实现权限校验

经过一天左右的学习,终于将Acegi权限校验框架看懂了。以下是本人的一个小Demo:
先设计数据库:
数据库名Acegi:
表User: id,name,password,enable
表RoleInfo:id,rolename,roledesc
表UserRole:id,user_id,user_name,role_id,role_name
其中向User表中插入三组数据
1 Tom 123 1
2 Jake 123 0
3 Rose 123 1

向RoleInfo中插入两组数据
1 ROLE_ADMIN 管理员角色
2 ROLE_USER 普通用户角色

向UserRole中插入三组角色
1 1 Tom 2 ROLE_USER
2 2 Jake 2 ROLE_USER
3 3 ROSE 1 ROLE_ADMIN

以上数据中表明:Tom是普通用户权限可用,Jake是普通用户权限但不可用,Rose是管理员权限可用。

需要配置两个配置文件,分别是web.xml,ApplicationContext_acegi.xml
虽然框架中包含了struts2和Spring,但配置acegi的时候跟struts2没有丝毫关系.
Spring中的配置文件也只需要配置相应的Bean就可以了。

首先是web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!-- Spring ApplicationContext配置文件的路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
[color=red]<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-acegi.xml</param-value>[/color]

</context-param>

<!-- Character Encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>

<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>false</param-value>
</init-param>
</filter>

[color=red]<!-- 配置acegi权限管理 过滤器链代理 (该配置一定要在struts2配置前才可以对struts2进行过滤)-->[/color] <filter>
<filter-name>acegiFilterChain</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<!-- 从JVM中查找类名一致的类,交由该类处理真正的Web过滤 -->
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>acegiFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Spring集成 struts2.0 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 配置log4j -->
<!-- Web 项目 Spring 加载 Log4j 的监听 -->
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>

<!--Spring ApplicationContext -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<!-- Spring Introspector -->
<listener>
<listener-class>
org.springframework.web.util.IntrospectorCleanupListener
</listener-class>
</listener>

</web-app>



下面是applicationContext_acegi.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

<!-- acegi安全框架 配置文件 主要配置: 安全拦截器, 认证管理器, 决策管理器. -->

<!-- ===========认证过滤器 用于拦截指定URL======= -->
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<!-- 指定认证管理器 -->
<property name="authenticationManager"
ref="authenticationManager" />
<!-- 登录失败后的URL -->
<property name="authenticationFailureUrl"
value="/logerror.jsp" />
<!-- 登录成功后的URL -->
<property name="defaultTargetUrl" value="/main.jsp" />
<!-- 指定要拦截的URL :登录URL -->
<property name="filterProcessesUrl" value="/acegi_security" />
<!-- 采用RemeberMe机制 注入 RememberMeServices -->
<property name="rememberMeServices" ref="rememberMeServices" />
</bean>

<!--================ 认证管理器=============== -->
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<!-- 认证服务提供者的实现类列表 -->
<ref bean="daoAuthenticationProvider" /> <!-- 基于DAO认证 -->
<ref bean="rememberMeAuthenticationProvider" /> <!-- 实现RemeberMe机制 认证 -->
</list>
</property>
</bean>

<!--================ 基于DAO验证的AuthenticationProvider ======= -->
<bean id="daoAuthenticationProvider"
class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</bean>

<!-- 此处自定义验证类,实现UserDetailsService -->
<bean id="userDetailsService"
class="com.zj.data.AcegiUserDeitailsService">
<property name="userDao" ref="userDao" />
<property name="userRoleDao" ref="userRoleDao" />
</bean>
<!--
也可以使用系统提供的InMemoryDaoImpl或jdbcDaoImpl
InMemoryDaoImpl用于实现配置文件验证
jdbcDaoImpl用于实现数据库验证
-->

<!--================ 基于RemeberMe机制的验证服务 ======= -->
<!-- RememberMeAuthenticationProvider负责对基于Cookie的用户凭证信息进行验证 -->
<bean id="rememberMeAuthenticationProvider"
class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="obullxl@163.com" /><!-- cookie中加密串关键字 -->
</bean>

<bean id="rememberMeServices"
class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<!-- 注入userDetailsService,从而获取Authentication对象 -->
<property name="userDetailsService" ref="userDetailsService" />

<property name="parameter" value="j_remember_me" />
<!-- 设置key值,防止加密串被恶意篡改 -->
<property name="key" value="obullxl@163.com" />
<!-- cookie的有效期 单位为秒 -->
<property name="tokenValiditySeconds" value="31536000" />
</bean>

<!-- ========================= 过滤器链 其中可以定义多个过滤器========== -->
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
<![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,rememberMeFilter,exceptionFilter,securityInterceptor,authenticationProcessingFilter

]]>
</value>
</property>
</bean>

<!-- ======HttpSessionContextIntegrationFilter 负责完成Acegi上下文与HTTP Session同步 =========== -->
<bean id="httpSessionContextIntegrationFilter"
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" />

<!-- ====== 系统退出过滤器 -->
<bean id="logoutFilter"
class="org.acegisecurity.ui.logout.LogoutFilter">
<!-- 登录退出后的URL -->
<constructor-arg value="/" />
<constructor-arg>
<list>
<ref bean="rememberMeServices" />
<bean
class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
</list>
</constructor-arg>
<!-- 登录退出的URL -->
<property name="filterProcessesUrl" value="/index.jsp" />
</bean>


<bean id="rememberMeFilter"
class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager"
ref="authenticationManager" />
<property name="rememberMeServices" ref="rememberMeServices" />
</bean>

<!-- ExceptionTranslationFilter 负责处理认证和授权中出现的异常。如果出现异常,调用EntryPoint -->
<bean id="exceptionFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter">
<!-- 出现AuthenticationException时的登录入口 -->
<property name="authenticationEntryPoint">
<bean
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.jsp" />
<property name="forceHttps" value="false" />
</bean>
</property>
<!-- 出现AccessDeniedException时的Handler -->
<property name="accessDeniedHandler">
<bean
class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/logerror.jsp" />
</bean>
</property>
</bean>

<!-- ==== 负责完成用户的授权。给受保护的Web资源指定角色,指定授权策略 ===== -->
<bean id="securityInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<!-- 指派认证管理器 -->
<property name="authenticationManager"
ref="authenticationManager" />
<!-- 指派访问策略管理器 -->
<property name="accessDecisionManager"
ref="accessDecisionManager" />
<!-- Web资源/角色信息,写死在配置文件中 一般用于演示 -->
<property name="objectDefinitionSource">
<value>
<![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=ROLE_ADMIN
/user/**=ROLE_USER
]]>
</value>
</property>
</bean>

<!-- ========================= 决策授权管理器 ========================= -->
<bean id="accessDecisionManager"
class="org.acegisecurity.vote.AffirmativeBased">
<!-- 指派投票策略 -->
<property name="decisionVoters">
<list>
<ref bean="roleVoter" />
</list>
</property>
<!-- 是否全部弃权就通过 -->
<property name="allowIfAllAbstainDecisions" value="false" />
</bean>
<!-- ================= 投票策略实现 ===========-->
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
<property name="rolePrefix" value="ROLE_" />
</bean>
</beans>


配置文件中有相应的注解,我就不多说啦。
下一步写一个自定义的权限校验类:
package com.zj.data;

import java.util.List;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import com.zj.dao.UserDao;
import com.zj.dao.UserRoleDao;
import com.zj.entity.User;
import com.zj.entity.UserRole;

public class AcegiUserDeitailsService implements UserDetailsService {

/* 依赖注入 */
private UserDao userDao;
private UserRoleDao userRoleDao;

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

public void setUserRoleDao(UserRoleDao userRoleDao) {
this.userRoleDao = userRoleDao;
}

/* 用户所有的权限 */
//private final List<GrantedAuthority> grantedAuthList = new ArrayList<GrantedAuthority>(6);
private GrantedAuthority[] grantedAuthArray;

/**实现接口UserDetailsService的函数,根据用户名获取UserDetails对象*/
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {

/* 取得用户 */
User user = userDao.getUserByName(userName);
if(user == null || user.getEnable()==0) {
throw new UsernameNotFoundException("User name is not found.");
}

/* 取得所有用户权限 */
List<UserRole> userRoleList = userRoleDao.getUserRoleByUserName(userName);
if(userRoleList == null || userRoleList.size() == 0) {
throw new UsernameNotFoundException("UserRole is not found.");
}
/* 取得用户的所有角色 */
int size = userRoleList.size();
grantedAuthArray = new GrantedAuthority[size];
int j = 0;
for(int i = 0; i < size; i++) {
UserRole userRole = userRoleList.get(i);
if(userRole != null) {
this.grantedAuthArray[j++] = new GrantedAuthorityImpl(userRole.getRolename().toUpperCase());

}
}
return new org.acegisecurity.userdetails.User(userName, user.getPassword(),
true, true, true, true, this.grantedAuthArray);
}
}

以上的UserDao 和 UserRoleDao的功能跟普通的DAO一样,这里就不多说啦。

下一步创建几个页面,实现表单提交,身份验证.
/admin/adminLogin.jsp 管理员权限才可以进行访问
/user/userLogin.jsp 普通用户权限就可以访问
/login.jsp 无权限设置
/main.jsp 登录成功的页面
/loginerror.jsp 访问出错以后跳转页面
基本流程如下:首先访问login.jsp,成功登录以后跳转到main.jsp,在main.jsp中有两个URL,一个访问admin/adminLogin.jsp,一个访问user/userLogin.jsp,
当Tom登录时,可以进入main.jsp,即可以成功登录,可以访问user/userLogin.jsp,但不可以访问admin/adminLogin.jsp
Jake无法进入main.jsp,即无法成功登录
Rose成功登录以后,即可以访问user/userLogin.jsp,也可以访问admin/adminLogin.jsp
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值