一、spring security--自定义过滤器
1、在上一篇的基础上,我们修改springSecuritySimple-config.xml文件
首先,我们要理解一个过滤器是怎么工作的,它主要依赖于下面三个部分:
AuthenticationManager认证管理器,实现用户认证入口
AccessDecisionManager:访问控制策略管理器,决策某个用户拥有的角色
securityMetadataSource:资源源数据定义,定义某一资源能被什么角色访问
我们使用的其实依旧是默认过滤器链中org.springframework.security.web.access.intercept.FilterSecurityInterceptor过滤器,只不过我们将其中重要的认证管理和资源源数据定义换成自己的东西,在AuthenticationManager中,我们不再采用以前获取数据的三种方式,而是用自定义的UserDetailService获取登陆用户信息,并赋值给认证管理器,在securityMetadataSource中,我们将url资源库中所有的url以及其匹配的角色进行了初始化,然后将每一个url请求和初始化数据比对,以判断是否授权用户。
2、MyUserDetailServiceImpl
我抽取了一个接口MyUserDetailService,接口继承org.springframework.security.core.userdetails.UserDetailsService
3、MySecurityMetadataSource
4、这样,我们以hj@163.com为例,实现用户角色和资源绑定的效果
eg.hj@163.com用户拥有ROLE_ADMIN角色,在登录访问"/securityLogin.do"url时,如果resource资源库中"/securityLogin.do"没有ROLE_ADMIN角色,该用户没有权限权限,应跳转到403页面,
用户角色:ROLE_ADMIN
用户角色:ROLE_GUEST
请求url:/securityLogin.do
请求url匹配角色:nobody
如果resource资源库中"/securityLogin.do"有ROLE_ADMIN角色,该用户才能访问
用户角色:ROLE_ADMIN
用户角色:ROLE_GUEST
请求url:/securityLogin.do
请求url匹配角色:ROLE_ADMIN
5、有了上面的基础,下面来设计用户权限管理
首先是在无用户状态下需要访问的url,不需要过滤器验证
其次设计一些公共url资源,并赋予给每个角色
在MySecurityMetadataSource类中添加loadPublicResources方法,并在初始化方法loadResourceDefine中调用
这样一来,每个注册用户可以访问/*一级资源和"/owner/**二级地址下所有资源,其他二级资源就可以在resource表中指定,并指派给相应的role了
1、在上一篇的基础上,我们修改springSecuritySimple-config.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" access-denied-page="/403.jsp" > <!-- 拦截器 --> <intercept-url pattern="/**" access="ROLE_ADMIN" /> <intercept-url pattern="/login.jsp" filters="none"/> <intercept-url pattern="/loginError.do" filters="none"/> <intercept-url pattern="/redirectAddUser.do" filters="none"/> <intercept-url pattern="/common/**" filters="none"/> <intercept-url pattern="/styles/**" filters="none"/> <!-- 用户登陆 --> <form-login login-page="/login.jsp" always-use-default-target="true" default-target-url="/securityLogin.do" authentication-failure-url="/loginError.do" /> <!-- 用户注销 --> <logout logout-success-url="/login.jsp" invalidate-session="true" /> <!-- session管理 --> <session-management invalid-session-url="/sessionTimeout.do" session-fixation-protection="migrateSession"> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/> </session-management> <!-- 在过滤器链中加入自定义过滤器 --> <custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/> <http-basic/> </http> <!-- 在自定义的过滤器中需要三个部分: AuthenticationManager认证管理器,实现用户认证入口 AccessDecisionManager:访问控制策略管理器,决策某个用户拥有的角色 securityMetadataSource:资源源数据定义,定义某一资源能被什么角色访问 FilterSecurityInterceptor.setSecurityMetadataSource()需要一个FilterSecurityMetadataSource实例, 它是SecurityMetadataSource的子类 --> <beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <beans:property name="authenticationManager" ref="authenticationManager" /> <beans:property name="accessDecisionManager" ref="accessDecisionManager" /> <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" /> </beans:bean> <!-- 认证管理器,别名注入,myUserDetailService通过注解的方式在程序中注入 --> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <password-encoder ref="md5Encoder"> <salt-source user-property="username"/> </password-encoder> </authentication-provider> </authentication-manager> <!-- 注入自定义加密器 --> <beans:bean id="md5Encoder" class="com.cpkf.notpad.security.impl.MD5EncoderImpl"/> <!-- 访问控制策略管理器 allowIfAllAbstainDecisions:通过投票机制决定是否访问某资源,false-一个以上的decisionVoters通过,则授权通过 --> <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <beans:property name="allowIfAllAbstainDecisions" value="false" /> <beans:property name="decisionVoters"> <beans:list> <beans:bean class="org.springframework.security.access.vote.RoleVoter"> <beans:property name="rolePrefix" value="ROLE_" /> </beans:bean> <beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" /> </beans:list> </beans:property> </beans:bean> <!-- 注入资源源数据定义 --> <beans:bean id="mySecurityMetadataSource" class="com.cpkf.notpad.security.impl.MySecurityMetadataSource" init-method="loadResourceDefine" /> </beans:beans>
首先,我们要理解一个过滤器是怎么工作的,它主要依赖于下面三个部分:
AuthenticationManager认证管理器,实现用户认证入口
AccessDecisionManager:访问控制策略管理器,决策某个用户拥有的角色
securityMetadataSource:资源源数据定义,定义某一资源能被什么角色访问
我们使用的其实依旧是默认过滤器链中org.springframework.security.web.access.intercept.FilterSecurityInterceptor过滤器,只不过我们将其中重要的认证管理和资源源数据定义换成自己的东西,在AuthenticationManager中,我们不再采用以前获取数据的三种方式,而是用自定义的UserDetailService获取登陆用户信息,并赋值给认证管理器,在securityMetadataSource中,我们将url资源库中所有的url以及其匹配的角色进行了初始化,然后将每一个url请求和初始化数据比对,以判断是否授权用户。
2、MyUserDetailServiceImpl
我抽取了一个接口MyUserDetailService,接口继承org.springframework.security.core.userdetails.UserDetailsService
package com.cpkf.notpad.security.impl; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.cpkf.notpad.entity.Account; import com.cpkf.notpad.entity.Resource; import com.cpkf.notpad.entity.Role; import com.cpkf.notpad.security.MyUserDetailService; import com.cpkf.notpad.server.IAccountService; /** * Filename: MyUserDetailServiceImpl.java * Description: 用自定义的UserDetailService获取登陆用户信息,并赋值给认证管理器 * Company: * @author: Jiang.hu * @version: 1.0 * Create at: May 26, 2011 4:23:27 PM * modified: */ @Service("myUserDetailService") public class MyUserDetailServiceImpl implements MyUserDetailService { private static final Logger logger = Logger.getLogger(MyUserDetailServiceImpl.class); @Autowired private IAccountService accountService; public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { //取得用户 Account account = accountService.getAccountByEmail(username); if(account == null){ logger.info("Can not found any Account by given username:" + username); throw new UsernameNotFoundException("Can not found any Account by given username:" + username); } //取得用户角色 Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); if(!account.getRoles().isEmpty() && account.getRoles() != null){ Iterator<Role> roleIterator = account.getRoles().iterator(); while(roleIterator.hasNext()){ Role role = roleIterator.next(); GrantedAuthority grantedAuthority = new GrantedAuthorityImpl(role.getRoleName().toUpperCase()); System.out.println("用户角色:" + role.getRoleName().toUpperCase()); authorities.add(grantedAuthority); } } return new User(username, account.getPassWord(), true, true, true, true, authorities); } }
3、MySecurityMetadataSource
package com.cpkf.notpad.security.impl; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.AntUrlPathMatcher; import org.springframework.security.web.util.UrlMatcher; import com.cpkf.notpad.entity.Resource; import com.cpkf.notpad.entity.Role; import com.cpkf.notpad.server.IResourceService; /** * Filename: MySecurityMetadataSource.java * Description: 资源源数据定义,决定某一资源能被什么角色访问 * Company: * @author: Jiang.hu * @version: 1.0 * Create at: May 26, 2011 5:04:50 PM * modified: */ public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private static final Logger logger = Logger.getLogger(MySecurityMetadataSource.class); @Autowired private IResourceService resourceService; private static Map<String, Collection<ConfigAttribute>> resourceMap = null; private UrlMatcher urlMatcher; public MySecurityMetadataSource(){ urlMatcher = new AntUrlPathMatcher(); resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); //可在构造方法中调用初始化方法,也可在配置文件中指定初始化方法 // loadResourceDefine(); } /* * method name : loadResourceDefine * description : 初始化方法,得到所有资源以及每个资源对应的角色 * @author : Jiang.Hu * @param : * @return : void * Create at : May 27, 2011 2:38:26 PM * modified : */ public void loadResourceDefine(){ List<Resource> resources = resourceService.getAllResources(); if(resources != null && !resources.isEmpty()){ for(Resource resource : resources){ Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>(); Iterator<Role> roleIterator = resource.getRoles().iterator(); while(roleIterator.hasNext()){ Role role = roleIterator.next(); ConfigAttribute configAttribute = new SecurityConfig(role.getRoleName()); configAttributes.add(configAttribute); } resourceMap.put(resource.getUrl(), configAttributes); } } } /* * method name : getAttributes * description : 将请求url和资源库比较,符合则将资源库的角色定义赋值给当前请求url * @author : Jiang.Hu * modified : leo , May 27, 2011 * @see : @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object) */ public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { if((object == null) || !this.supports(object.getClass())){ logger.info("Object must be a FilterInvocation"); throw new IllegalArgumentException("Object must be a FilterInvocation"); } Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>(); if(object instanceof FilterInvocation){ String requestUrl = ((FilterInvocation)object).getRequestUrl(); System.out.println("请求url:" + requestUrl); //比较请求url和资源库url,匹配则赋予对应的角色权限 if(resourceMap != null && !resourceMap.isEmpty()){ Iterator<String> iterator = resourceMap.keySet().iterator(); while(iterator.hasNext()){ String resourceUrl = iterator.next(); if(urlMatcher.pathMatchesUrl(resourceUrl, requestUrl)){ configAttributes.addAll(resourceMap.get(resourceUrl)); } } if(configAttributes.isEmpty()){ configAttributes.add(new SecurityConfig("nobody")); } for(ConfigAttribute configAttribute : configAttributes){ System.out.println("请求url匹配角色:" + configAttribute.toString()); } return configAttributes; } } return null; } public Collection<ConfigAttribute> getAllConfigAttributes() { return new ArrayList<ConfigAttribute>(); } public boolean supports(Class<?> clazz) { return FilterInvocation.class.isAssignableFrom(clazz); } }
4、这样,我们以hj@163.com为例,实现用户角色和资源绑定的效果
eg.hj@163.com用户拥有ROLE_ADMIN角色,在登录访问"/securityLogin.do"url时,如果resource资源库中"/securityLogin.do"没有ROLE_ADMIN角色,该用户没有权限权限,应跳转到403页面,
用户角色:ROLE_ADMIN
用户角色:ROLE_GUEST
请求url:/securityLogin.do
请求url匹配角色:nobody
如果resource资源库中"/securityLogin.do"有ROLE_ADMIN角色,该用户才能访问
用户角色:ROLE_ADMIN
用户角色:ROLE_GUEST
请求url:/securityLogin.do
请求url匹配角色:ROLE_ADMIN
5、有了上面的基础,下面来设计用户权限管理
首先是在无用户状态下需要访问的url,不需要过滤器验证
<intercept-url pattern="/**" access="ROLE_ADMIN" /> <intercept-url pattern="/login.jsp" filters="none"/> <intercept-url pattern="/redirectAddUser.do" filters="none"/> <intercept-url pattern="/redirectRegist.do" filters="none"/> <intercept-url pattern="/loginError.do" filters="none"/> <intercept-url pattern="/sessionTimeout.do" filters="none"/> <intercept-url pattern="/visualCode.do" filters="none"/> <intercept-url pattern="/addAccount.do" filters="none"/> <intercept-url pattern="/styles/**" filters="none"/> <intercept-url pattern="/scripts/**" filters="none"/> <intercept-url pattern="/images/**" filters="none"/>
其次设计一些公共url资源,并赋予给每个角色
package com.cpkf.notpad.commons.constants; /** * Filename: PublicResourceEnum.java * Description: 公共资源 * home-根目录下所有链接(/*不包含二级目录下请求,/**包含二级目录请求) * owner-owner下所有请求,用户相关资源eg修改个人资料等 * Company: * @author: Jiang.hu * @version: 1.0 * Create at: May 30, 2011 10:53:27 AM * modified: */ public enum PublicResourceEnum { OWNER("owner","/owner/**"),HOME("home","/*"); private String publicResourceName; private String publicResourcePath; private PublicResourceEnum(String publicResourceName, String publicResourcePath) { this.publicResourceName = publicResourceName; this.publicResourcePath = publicResourcePath; } public String getPublicResourceName() { return publicResourceName; } public String getPublicResourcePath() { return publicResourcePath; } }
在MySecurityMetadataSource类中添加loadPublicResources方法,并在初始化方法loadResourceDefine中调用
public void loadPublicResources(){ List<Role> roles = roleService.getAllRoles(); for(PublicResourceEnum publicResourceEnum : PublicResourceEnum.values()){ Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>(); for(Role role : roles){ ConfigAttribute configAttribute = new SecurityConfig(role.getRoleName()); configAttributes.add(configAttribute); } resourceMap.put(publicResourceEnum.getPublicResourcePath(), configAttributes); } }
这样一来,每个注册用户可以访问/*一级资源和"/owner/**二级地址下所有资源,其他二级资源就可以在resource表中指定,并指派给相应的role了
相关推荐
2. **过滤器链**:Spring Security通过一系列过滤器处理HTTP请求,这些过滤器在Web应用的Servlet容器中被配置和执行。 - `DelegatingFilterProxy`:这是Spring Security与Servlet容器交互的关键,它代理到Spring ...
3. **过滤器链**:Spring Security的核心在于其过滤器链,它拦截HTTP请求并应用安全策略。`FilterSecurityInterceptor`是其中的关键组件,负责根据配置的访问规则对请求进行处理。 4. **会话管理**:Spring ...
本实例主要面向初学者,通过一个基于Maven的项目,帮助你快速上手Spring Security。 首先,让我们了解Maven。Maven是一个项目管理工具,它能够管理项目的构建、依赖关系和文档。在Spring Security实例中,Maven用于...
- **配置 web.xml**:在 web.xml 文件中配置 Spring Security 的过滤器链。 - **最小 `<http>` 配置**:使用 `<http>` 元素可以轻松地配置 HTTP 认证和授权规则。 - **自动配置**:`auto-config` 属性可以自动配置...
根据提供的文件信息,我们可以深入探讨如何使用Maven和Spring Security框架来构建一个安全的应用程序。以下将详细解析各个部分,并介绍这些配置是如何协同工作来确保应用程序的安全性的。 ### Maven依赖 在项目中...
- **配置过滤器**:使用Spring Security控制权限的第一步是在`web.xml`中添加Spring Security过滤器的配置。这通常涉及到定义过滤器映射以及初始化参数等。 - **使用命名空间配置方式**:从2.0版本开始,Spring ...
1. **Filter Security Chain**:这是Spring Security的核心,一系列过滤器负责拦截请求,执行安全相关的操作。 2. **Authentication Manager**:负责处理用户的认证请求,包括验证用户名和密码。 3. **...
4. **过滤器集成**:Acegi Security通过Servlet过滤器与Spring MVC无缝集成,可以在HTTP请求进入应用之前进行安全检查。 5. **异常处理**:能够统一处理安全相关的异常,如未认证、未授权等,提供定制化的错误提示...
Maven 是一个项目管理和综合工具,它管理项目的构建、报告和文档生成。在本项目中,我们使用Maven来管理依赖关系,构建项目,并确保所有必要的库都已正确引入。Spring Security 作为依赖项,可以通过在`pom.xml`文件...
- 通过源码分析,了解Spring Security的拦截器如何工作,以及如何自定义安全规则。 - 查看`SecurityConfig`类,这是Spring Security的核心配置,它扩展了`WebSecurityConfigurerAdapter`并覆盖了一些关键方法。 -...
在本项目中,我们主要关注的是一个基于Spring MVC 4.1、Spring 4.1、MyBatis 3.2以及Spring Security 3.2的Maven环境的搭建过程。下面将详细介绍这些技术栈的核心概念、它们如何协同工作以及如何在实际开发环境中...
- **添加自定义过滤器**: 如何向 Spring Security 添加自定义的安全过滤器。 - **设置自定义认证入口点**: 如何配置自定义的认证入口点。 - **方法安全**: - **`<global-method-security>` 元素**: 介绍该元素...
本实战资源包含四个小项目,每个项目都基于Maven构建。Maven是一个项目管理和综合工具,能够帮助开发者管理项目依赖、构建过程以及生成文档。在Spring Security项目中,Maven的pom.xml文件定义了所有必要的依赖,如...
【标题】"spring-security-helloworld" 是一个基于Spring Security框架的简单示例项目,它用于初学者理解并实践Spring Security的基础用法。Spring Security是一个强大的安全框架,为Java应用程序提供了全面的安全...
2. **spring-security-web-3.1.3.RELEASE.jar**:这个模块专注于Web安全,包含处理HTTP请求的安全过滤器链。如`FilterSecurityInterceptor`和`DelegatingFilterProxy`等,它们在Spring MVC或者Servlet容器中拦截请求...
1. **过滤器链**:Spring Security通过一系列过滤器来拦截HTTP请求,执行身份验证和授权过程。 2. **AuthenticationManager**:负责处理认证请求,验证用户提供的凭证,如用户名和密码。 3. **UserDetailsService**...
同时,开发人员可以将自定义过滤器添加到过滤器链中,以实现更为复杂的安全需求。 在理解Spring Security Reference时,需注意文档中可能存在的OCR扫描错误,应当对这些错误进行合理的推断和修正,确保对文档内容的...
增强了 Web 应用的安全性,例如改进了 CSRF 攻击防御机制、增强过滤器链配置灵活性等。 ##### 2.3 授权改进 在授权方面进行了改进,例如增加了新的授权策略和方法,提高了授权过程的灵活性。 ##### 2.4 加密模块...
根据提供的标题、描述、标签以及部分链接内容,我们可以推断出该主题主要涉及Spring Boot、MyBatis、Spring Security和Redis等技术栈的综合运用。接下来,我们将详细探讨这些技术的关键知识点及其在实际项目中的应用...
这个"spring-security-4.2.0.RELEASE-dist"压缩包包含了Spring Security 4.2.0版本的全部资源,它允许开发者快速地集成到自己的项目中,特别是对于那些在官方下载速度较慢的地区。 在Spring Security 4.2.0中,主要...