1:spring security 对于普通的URL权限验证基于过滤器实现的
在web.xml 文件中这样配置
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter>
其中 filter-name一定要配成springSecurityFilterChain,因为DelegatingFilterProxy初始化的时候回根据配置的filter-name 从容器中查找对因的spring security 统一处理过滤器 返回的是FilterChainProxy 。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); //根据请求的URL 放回相应的过滤器 List filters = getFilters(fi.getRequestUrl()); if (filters == null || filters.size() == 0) { if (logger.isDebugEnabled()) { logger.debug(fi.getRequestUrl() + filters == null ? " has no matching filters" : " has an empty filter list"); } chain.doFilter(request, response); return; } //构建spring security 过滤器链对象 VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters); virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse()); }
根据Url返回过滤器其中会包含一个FilterSecurityInterceptor过滤器,这个是专门处理http url 权限认证的过滤器,下面是他的doFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public void invoke(FilterInvocation fi) throws IOException, ServletException { if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest) { // filter already applied to this request and user wants us to observce // once-per-request handling, so don't re-do security checking fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } else { // first time this request being called, so perform security checking if (fi.getRequest() != null) { fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); } //这个方法是权限验证的入口调用父类的beforeInvocation方法 InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } }
在上面我们看到invoke 方法会调用父类的beforeInvocation方法。父类是AbstractSecurityInterceptor,这个类是权限验证的主类,
包含子类有
- EndpointInterceptor
- FilterSecurityInterceptor 对应http资源过滤
- MethodSecurityInterceptor 对应spring aop 拦截过滤
- AspectJSecurityInterceptor
- AspectJAnnotationSecurityInterceptor
protected InterceptorStatusToken beforeInvocation(Object object) { Assert.notNull(object, "Object was null"); if (!getSecureObjectClass().isAssignableFrom(object.getClass())) { throw new IllegalArgumentException("Security invocation attempted for object " + object.getClass().getName() + " but AbstractSecurityInterceptor only configured to support secure objects of type: " + getSecureObjectClass()); } //获取资源对应的权限配置 ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object); if (attr == null) { if (rejectPublicInvocations) { throw new IllegalArgumentException( "No public invocations are allowed via this AbstractSecurityInterceptor. " + "This indicates a configuration error because the " + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'"); } if (logger.isDebugEnabled()) { logger.debug("Public object - authentication not attempted"); } publishEvent(new PublicInvocationEvent(object)); return null; // no further work post-invocation } if (logger.isDebugEnabled()) { logger.debug("Secure object: " + object + "; ConfigAttributes: " + attr); } if (SecurityContextHolder.getContext().getAuthentication() == null) { credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound", "An Authentication object was not found in the SecurityContext"), object, attr); } //判断每次请求是否都需要进行认证检查 Authentication authenticated = authenticateIfRequired(); try { //权限验证 this.accessDecisionManager.decide(authenticated, object, attr); } catch (AccessDeniedException accessDeniedException) { AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated, accessDeniedException); publishEvent(event); throw accessDeniedException; } if (logger.isDebugEnabled()) { logger.debug("Authorization successful"); } AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated); publishEvent(event); // Attempt to run as a different user Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr); if (runAs == null) { if (logger.isDebugEnabled()) { logger.debug("RunAsManager did not change Authentication object"); } // no further work post-invocation return new InterceptorStatusToken(authenticated, false, attr, object); } else { if (logger.isDebugEnabled()) { logger.debug("Switching to RunAs Authentication: " + runAs); } SecurityContextHolder.getContext().setAuthentication(runAs); // revert to token.Authenticated post-invocation return new InterceptorStatusToken(authenticated, true, attr, object); } }
在上面方法中 this.accessDecisionManager.decide(authenticated, object, attr);才是资源授权的 地方,accessDecisionManager是授权访问管理器,默认实现由三种
(1)UnanimousBased(全票通过):所有投票器都通过才允许访问资源。
(2)ConsensusBased(少数服从多数):超过一半的投票器通过才允许访问资源。
(3)AffirmativeBased(一票通过):只要有一个投票器投票通过,就允许访问资源。
URL资源授权默认走AffirmativeBased这个授权访问管理器,其授权代码如下
public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException { //获取当前访问授权管理器的投票器 Iterator iter = this.getDecisionVoters().iterator(); int deny = 0; while (iter.hasNext()) { AccessDecisionVoter voter = (AccessDecisionVoter) iter.next(); int result = voter.vote(authentication, object, config); switch (result) { case AccessDecisionVoter.ACCESS_GRANTED: return; case AccessDecisionVoter.ACCESS_DENIED: deny++; break; default: break; } } if (deny > 0) { throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied")); } // To get this far, every AccessDecisionVoter abstained checkAllowIfAllAbstainDecisions(); }
Spring Security中有很多AccessDecisionVoter的实现,最简单的有RoleVoter。RoleVoter通过将Authentication里面获取的权限信息,与从ConfigAttributeDefinition配置的访问资源需要的权限对比,来投票通过,或拒绝,或弃权。代码如下
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) { int result = ACCESS_ABSTAIN; Iterator iter = config.getConfigAttributes().iterator(); GrantedAuthority[] authorities = extractAuthorities(authentication); while (iter.hasNext()) { ConfigAttribute attribute = (ConfigAttribute) iter.next(); if (this.supports(attribute)) { result = ACCESS_DENIED; // Attempt to find a matching granted authority for (int i = 0; i < authorities.length; i++) { if (attribute.getAttribute().equals(authorities[i].getAuthority())) { return ACCESS_GRANTED; } } } } return result; }
相关推荐
springsecurity3.0.5简单例子 当用firefox访问时产生的临时cookie,在下次访问中还存在的话,获取的session还是原来的session(user验证信息不变),如果把那个临时cookie删除的话,则springsecuriyt生成新的session...
在集成 Spring Security 安全框架的时候我们最先处理的可能就是根据我们项目的实际需要来定制注册登录了,尤其是 Http 登录认证。...我们只有把这个过滤器搞清楚才能做一些...今天我们就简单分析它的源码和工作流程。
本文介绍了Spring Security命名空间配置的核心概念,并说明了Web应用程序中基于表单的简单身份验证所需的设置。
当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的Shiro 就足够了。对于它俩到底哪个 好,这个不必纠结,能更简单的解决项目...
当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个 好,这个不必纠结,能更简单的解决...
当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目...
目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底...
目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底...
目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底...
当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的Shiro 就足够了。对于它俩到底哪个 好,这个不必纠结,能更简单的解决项目...
目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底...
当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个 好,这个不必纠结,能更简单的解决...
目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。...
而Spring Boot 是Spring 主推的基于“习惯优于配置”的原则,让你能够快速搭建应用的框架,从而使得Java EE 开发变得异常简单。 《JavaEE开发的颠覆者: Spring Boot实战》从Spring 基础、Spring MVC 基础讲起,从而...
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架, 在企业级应用中被广泛使用。本章节不会对该框架做深入探讨,仅从基于角色的权限管理角度,来实现对系统的权限...
而Spring Boot 是Spring 主推的基于“习惯优于配置”的原则,让你能够快速搭建应用的框架,从而使得Java EE 开发变得异常简单。 《JavaEE开发的颠覆者: Spring Boot实战》从Spring 基础、Spring MVC 基础讲起,从而...
当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个 好,这个不必纠结,能更简单的解决...
该在线考试系统毕业设计使用了spring MVC+spring+mybatis+Spring Security+maven技术,提供了随机练习、强化练习、错题管理、 模拟考试、统计分析等功能,可以通过它快捷方便的创建试题和题库,发布试卷,组织考试,...
而Spring Boot 是Spring 主推的基于“习惯优于配置”的原则,让你能够快速搭建应用的框架,从而使得Java EE 开发变得异常简单。 《JavaEE开发的颠覆者: Spring Boot实战》从Spring 基础、Spring MVC 基础讲起,从而...
ring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所 以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。 ...