Spring Security 可动态授权RBAC权限模块实践
来源:互联网 发布:南方 中金环境 知乎 编辑:程序博客网 时间:2024/04/30 12:14
先在web.xml 中配置一个过滤器(必须在Struts的过滤器之前)
<filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping>
然后就是编写Spring安全的配置文件applicationContext-security.xml并配置到Spring解析的路径下
Spring Security主要做两件事,一件是认证,一件是授权。
认证
在http标签中的
<form-login login-page="/page/login.jsp" />
配置。且该登录页面必须是不被拦截的。故要配置上
<intercept-url pattern="/page/login.jsp" filters="none" />
Web项目的认证如果在HTTP标签中配置了auto-config="true",框架就会自动的配置多8?个拦截器。 默认表单登录认证的是FORM_LOGIN_FILTER拦截器,我们可以直接写自定义的UserDetailsService,在这个类中实现方法UserDetails loadUserByUsername(String username),从数据库获取用户信息,以及其拥有的角色。
@Service("myUserDetailsService")public class MyUserDetailsServiceImpl extends BaseService implements UserDetailsService {@Resourceprivate UserDao userDao;public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException, DataAccessException {User user = userDao.getUserByUsername(username);List<Role> roles = user.getRoles();Collection<GrantedAuthority> authorities = new LinkedList<GrantedAuthority>();for (Role role : roles) {authorities.add(new GrantedAuthorityImpl(role.getCode()));}UserDetails userDetails = new org.springframework.security.core.userdetails.User(username,user.getPassword(),Constants.STATE_VALID.equals(user.getState()),true,true,true,authorities);return userDetails;}}
配置在
<authentication-manager alias="myAuthenticationManager"><authentication-provider user-service-ref="myUserDetailsService"><password-encoder hash="md5" /></authentication-provider></authentication-manager>
如果需要在登录的时候,在HTTP SESSION中配置做些操作的。就得配置自定义的FORM_LOGIN_FILTER了在HTTP标签中加入
<custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER" />
并配置
<!-- 访问控制验证器Authority --><beans:bean id="securityFilter"class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"><beans:property name="authenticationManager" ref="myAuthenticationManager" /><beans:property name="accessDecisionManager"ref="affirmativeBasedAccessDecisionManager" /><beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"/></beans:bean>
MyUsernamePasswordAuthenticationFilter 类是这么写的
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{public static final String USERNAME = "username";public static final String PASSWORD = "password";@Resourceprivate LoginService loginService;private UserLoginFormBean userLoginFormBean = new UserLoginFormBean();@Resourceprivate LogService logService;@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {String username = obtainUsername(request);String password = obtainPassword(request);HttpSession session = request.getSession();userLoginFormBean.setUsername(obtainUsername(request));userLoginFormBean.setPassword(obtainPassword(request));User user = loginService.login(userLoginFormBean);session.setAttribute(Constants.SESSION_USER, user);Log log = new Log(user,getIpAddr(request),"用户登录", null);logService.add(log);//UsernamePasswordAuthenticationToken实现 AuthenticationUsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);// Place the last username attempted into HttpSession for views// 允许子类设置详细属性 setDetails(request, authRequest); // 运行UserDetailsService的loadUserByUsername 再次封装Authenticationreturn this.getAuthenticationManager().authenticate(authRequest);}}
getAuthenticationManager().authenticate(authRequest)是为了让UserDetailService提供Detailed的信息并认证
授权
在授权时,系统默认通过FILTER_SECURITY_INTERCEPTOR认证。
如需自定义授权拦截器,我们在HTTP中在默认授权拦截器前配置了自定义的拦截器
<custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" />
本平台采用基于请求URL地址的验证方式
securityFilter的配置如下
<!-- 访问控制验证器Authority --><beans:bean id="securityFilter"class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"><beans:property name="authenticationManager" ref="myAuthenticationManager" /><beans:property name="accessDecisionManager"ref="affirmativeBasedAccessDecisionManager" /><beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"/></beans:bean>
采用默认的自定义的也是采用Spring默认的FilterSecurityInterceptor拦截器,accessDecisionManager也采用的是框架提供的affirmativeBasedAccessDecisionManager
采用投票者来判断是否授权。
<beans:bean id="affirmativeBasedAccessDecisionManager"class="org.springframework.security.access.vote.AffirmativeBased"><beans:property name="decisionVoters" ref="roleDecisionVoter" /></beans:bean><beans:bean name="roleDecisionVoter"class="org.springframework.security.access.vote.RoleVoter" /><beans:bean id="mySecurityMetadataSource"class="org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource"><beans:constructor-argtype="org.springframework.security.web.util.UrlMatcher" ref="antUrlPathMatcher" /><beans:constructor-arg type="java.util.LinkedHashMap"ref="securityRequestMapFactoryBean" /></beans:bean>
SecurityMetadataSource也是ss web框架提供的DefaultFilterInvocationSecurityMetadataSource,只是初始化参数中,一个选择antUrl匹配,还是正则匹配,另一个是提供自定义的通过securityRequestMapFactoryBean。在后者是一个LinkedHashMap<RequestKey, Collection<ConfigAttribute>>类型,就是每一个URL匹配模式,所需要角色的集合。
@Service("securityRequestMapFactoryBean")public class SecurityRequestMapFactoryBean extendsLinkedHashMap<RequestKey, Collection<ConfigAttribute>> {@Resourceprivate ModuleDao moduleDao;@PostConstructpublic void loadSecurityInfos(){List<Module> modules = moduleDao.getAll(new Module());//List<Role> roles = roleDao.getAll(new Role());for (Module module : modules) {RequestKey requestKey = new RequestKey(module.getPageUrl());Collection<ConfigAttribute> configAttributes = new LinkedList<ConfigAttribute>();for (final Role role : module.getRoles()) {configAttributes.add(new ConfigAttribute() {public String getAttribute() {return role.getCode();}});}this.put(requestKey, configAttributes);}}}
PS: 最终的件applicationContext-security.xml配置文件
<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"><http auto-config="true"><intercept-url pattern="/page/login.jsp" filters="none" /><intercept-url pattern="/LoginAction*" filters="none" /><intercept-url pattern="/common/**" filters="none" /><intercept-url pattern="/css/**" filters="none" /><intercept-url pattern="/common/**" filters="none" /><intercept-url pattern="/images/**" filters="none" /><intercept-url pattern="/js/**" filters="none" /><form-login login-page="/page/login.jsp" /><custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER" /><custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" /></http><!-- 访问控制验证器Authority --><beans:bean id="securityFilter"class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"><beans:property name="authenticationManager" ref="myAuthenticationManager" /><beans:property name="accessDecisionManager"ref="affirmativeBasedAccessDecisionManager" /><beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"/></beans:bean><!-- 登录验证器Authentication --><beans:bean id="loginFilter"class="com.epro.crm.util.security.MyUsernamePasswordAuthenticationFilter"><!-- 处理登录的action --><beans:property name="filterProcessesUrl" value="/SecurityCheck" /><!-- 验证成功后的处理--><beans:property name="authenticationSuccessHandler"ref="loginLogAuthenticationSuccessHandler" /><!-- 验证失败后的处理--><beans:property name="authenticationFailureHandler"ref="simpleUrlAuthenticationFailureHandler" /><beans:property name="authenticationManager" ref="myAuthenticationManager" /><!-- 注入DAO为了查询相应的用户 --><beans:property name="loginService" ref="loginService" /><beans:property name="logService" ref="logService" /></beans:bean><authentication-manager alias="myAuthenticationManager"><authentication-provider user-service-ref="myUserDetailsService"><password-encoder hash="md5" /></authentication-provider></authentication-manager><beans:bean id="mySecurityMetadataSource"class="org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource"><beans:constructor-argtype="org.springframework.security.web.util.UrlMatcher" ref="antUrlPathMatcher" /><beans:constructor-arg type="java.util.LinkedHashMap"ref="securityRequestMapFactoryBean" /></beans:bean><beans:bean id="antUrlPathMatcher"class="org.springframework.security.web.util.AntUrlPathMatcher" /><beans:bean id="affirmativeBasedAccessDecisionManager"class="org.springframework.security.access.vote.AffirmativeBased"><beans:property name="decisionVoters" ref="roleDecisionVoter" /></beans:bean><beans:bean name="roleDecisionVoter"class="org.springframework.security.access.vote.RoleVoter" /><beans:bean id="loginLogAuthenticationSuccessHandler"class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"><beans:property name="defaultTargetUrl" value="/page/main.jsp"></beans:property></beans:bean><beans:bean id="simpleUrlAuthenticationFailureHandler"class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"><!--可以配置相应的跳转方式。属性forwardToDestination为true采用forward false为sendRedirect--><beans:property name="defaultFailureUrl" value="/page/login.jsp"></beans:property></beans:bean><!-- 未登录的切入点 --><beans:bean id="authenticationProcessingFilterEntryPoint"class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"><beans:property name="loginFormUrl" value="/page/login.jsp"></beans:property></beans:bean></beans:beans>
------------------------------------------------------ 分割线 -----------------------------------------------------------------
后记:由于权限配置信息,是由初始化mySecurityMetadataSource时,就由mySecurityMetadataSource读取提供的权限信息,并缓存与该类的私有成员变量中,所以重新加载时就需要重新新建一个对象public void loadSecurityInfos(){this.clear();List<Module> modules = moduleDao.getAll(new Module());Collections.sort(modules);for (Module module : modules) {RequestKey requestKey = new RequestKey(module.getPageUrl());Collection<ConfigAttribute> configAttributes = new LinkedList<ConfigAttribute>();moduleDao.refresh(module);List<Role> roles = module.getRoles();if(roles != null){for (final Role role : roles) {configAttributes.add(new ConfigAttribute() {public String getAttribute() {return role.getCode();}});}}this.put(requestKey, configAttributes);log.info(module.getName()+ "模块 URL模式:" + requestKey + " 授权角色:"+ roles);}}
- Spring Security 可动态授权RBAC权限模块实践
- Spring Security 可动态授权RBAC权限模块实践
- 修改spring security源码实现动态授权
- Spring Security实现动态权限管理
- 使用Spring Security、Spring Data Jpa实现的RBAC权限控制
- 使用Spring Security、Spring Data Jpa实现的RBAC权限控制
- 传智播客-- 教育办公系统集成 spring-security 框架实现权限模块
- 教育办公系统集成 spring-security 框架实现权限模块
- Spring Security 授权通知类
- Spring Security 3.0数据库动态实现权限控制
- Spring Security 3.0 数据库动态实现权限控制
- spring security 4.1添加验证码和动态权限管理
- Spring Security系列四 自定义决策管理器(动态权限码)
- spring security 3 实践
- spring security实践
- Spring Security实践
- Spring Security 权限说明
- spring security 权限验证
- Asp.net 2.0 中的TreeView的右键菜单
- winform调用config文件
- DNS报文格式
- 在Qt中使用sleep (转)
- Linux命令:检查系统资源变化(vmstat)!
- Spring Security 可动态授权RBAC权限模块实践
- Entity Framework使用建模之Database First A
- js 正则表达式中的特殊字符
- RGB与HSB之间的转换公式
- linux 动态库和静态库的编译
- 用 TigerVNC 实现 Linux 远程桌面
- 111111111
- 在Qt中如何编写插件,加载插件和卸载插件
- dropdownlist和textbox获取问题