`
myCsdn_taoge
  • 浏览: 40366 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
文章分类
社区版块
存档分类
最新评论

SpringSecurity工作原理小解读

 
阅读更多
  •   SecurityContextPersistenceFilter
  •   ConcurrentSessionFilter
  •   WebAsyncManagerIntegrationFilter
  •   HeaderWriterFilter
  •   CsrfFilter
  •   LogoutFilter
  •   UsernamePasswordAuthenticationFilter
  •   DefaultLoginPageGeneratingFilter
  •   RequestCacheAwareFilter
  •   SecurityContextHolderAwareRequestFilter
  •   RememberMeAuthenticationFilter
  •   AnonymousAuthenticationFilter
  •   SessionManagementFilter
  •   ExceptionTranslationFilter
  •   FilterSecurityInterceptor

 

如果要在我们自己的项目中整合SpringSecurity,,应该实现SpringSecurity里面的UserDetailsService,并且将USer权限authorities.add(new SimpleGrantedAuthority(role.getId()));将权限存放到实体的当中,同时User实体要实现UserDetails这个接口,这个接口里面的内容为:

package org.springframework.security.core.userdetails;

import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;

public abstract interface UserDetails
  extends Serializable
{
  public abstract Collection<? extends GrantedAuthority> getAuthorities();//这个是权限相关
  
  public abstract String getPassword();
  
  public abstract String getUsername();
  
  public abstract boolean isAccountNonExpired();
  
  public abstract boolean isAccountNonLocked();
  
  public abstract boolean isCredentialsNonExpired();
  
  public abstract boolean isEnabled();
}

 所在在User里获取相关权限代码可以这样写:

Collection authorities = new ArrayList();

   

     List<Role> roles = user.getRoles();//获取该用户所拥有的权限

      for (Role role : roles) {

       authorities.add(new SimpleGrantedAuthority(role.getId()));

      }

 

   user.setAuthorities(authorities);

 

下面是SpringSecurity里面的实体User类:

package org.springframework.security.core.userdetails;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

public class User
  implements UserDetails, CredentialsContainer
{
  private static final long serialVersionUID = 320L;
  private String password;
  private final String username;
  private final Set<GrantedAuthority> authorities;
  private final boolean accountNonExpired;
  private final boolean accountNonLocked;
  private final boolean credentialsNonExpired;
  private final boolean enabled;

  public User(String username, String password, Collection<? extends GrantedAuthority> authorities)
  {
    this(username, password, true, true, true, true, authorities);
  }

  public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities)
  {
    if ((username == null) || ("".equals(username)) || (password == null)) {
      throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
    }

    this.username = username;
    this.password = password;
    this.enabled = enabled;
    this.accountNonExpired = accountNonExpired;
    this.credentialsNonExpired = credentialsNonExpired;
    this.accountNonLocked = accountNonLocked;
    this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
  }

  public Collection<GrantedAuthority> getAuthorities()
  {
    return this.authorities;
  }

  public String getPassword() {
    return this.password;
  }

  public String getUsername() {
    return this.username;
  }

  public boolean isEnabled() {
    return this.enabled;
  }

  public boolean isAccountNonExpired() {
    return this.accountNonExpired;
  }

  public boolean isAccountNonLocked() {
    return this.accountNonLocked;
  }

  public boolean isCredentialsNonExpired() {
    return this.credentialsNonExpired;
  }

  public void eraseCredentials() {
    this.password = null;
  }

  private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
    Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");

    SortedSet sortedAuthorities = new TreeSet(new User.AuthorityComparator(null));

    for (GrantedAuthority grantedAuthority : authorities) {
      Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
      sortedAuthorities.add(grantedAuthority);
    }

    return sortedAuthorities;
  }

  public boolean equals(Object rhs)
  {
    if ((rhs instanceof User)) {
      return this.username.equals(((User)rhs).username);
    }
    return false;
  }

  public int hashCode()
  {
    return this.username.hashCode();
  }

  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    sb.append(super.toString()).append(": ");
    sb.append("Username: ").append(this.username).append("; ");
    sb.append("Password: [PROTECTED]; ");
    sb.append("Enabled: ").append(this.enabled).append("; ");
    sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
    sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
    sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");
    boolean first;
    if (!this.authorities.isEmpty()) {
      sb.append("Granted Authorities: ");

      first = true;
      for (GrantedAuthority auth : this.authorities) {
        if (!first) {
          sb.append(",");
        }
        first = false;

        sb.append(auth);
      }
    } else {
      sb.append("Not granted any authorities");
    }

    return sb.toString();
  }
}

 

 

上面列的这些就是SS整个的过滤器集合,15个,非常多,其实web开发用到的过滤器没有那么多。简单的说过滤器作用在这里体现的就是 “检验 请求(request) 和 响应 (response)”具体哪些是对开发人员是要熟悉的, 待我们验证完就知道了!

 

那么在SS中是如何工作的呢?

完成基本的配置工作:web.xml 配置SS的相关信息
<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>
 
在web应用中,当浏览器发起一个请求到展现出一个页面的内容就是一个完成的请求和响应:
1、在这里过程中,request 是直接访问的资源URL, 未经过处理就返回了相关数据
2、或者是request 和 response 都经过了相关处理返回相关数据
 
SS就是走的第二种路, 在request和response都经过了一系列的处理。那么要处理这些请求和响应最好的方法就是Servlet过滤器了。至于处理了什么? 怎么处理的?我们再看!
 
SS 作为一种安全框架, 我们暂且先讨论的是web部分的安全问题,因为SS还可以给其他的客户端做安全处理。大概一个请求响应如下步骤:
1:浏览器的请求
2:过滤器拦截URL
3:认证授权
4:访问授权
 
一步步具体对这四个步骤进行解读
 
1、浏览器的请求
       发起一个标准的http协议的请求URL “http://www.access.com/resource/accountlist";
       上面的一个URL地址就是标准的HTTP协议的请求:协议头, 域名主体,端口80, 资源位置
 
2、过滤器拦截URL
     这里就涉及到了过滤器了,很想知道的是从请求发起的URL被什么过滤器拦截了?
      首页在SS中注册的过滤器有15种,即文章开头所列出来的,这15个过滤器分别被注入到了SS的过滤器链中,由Spring的IOC容器来管理。
      并且如果我们自己自定义的过滤器,实现了其上的任意中一种,那么也一样会注入到SS的过滤器链中被维护起来。
      所有的URL 都会经过这15个过滤器,每个过滤器执行不同的职责(比如:认证,授权,访问,内置对象的初始化等等)
      进入到这个过滤器的前提是被请求的URL地址是要需要经过SS的,那么如何让URL经过这些过滤器的拦截的呢?
 
      在Security.xml 配置文件中
 
         <http pattern="/resources/**" security="none"/>
 
        配置中所描述的就是以/resource/**  形式的URL 是不需要经过过滤器的处理的,其余的那么都会经过拦截器的处理。
        在这里大概阐述下这些拦截器做了什么事情,只列出web方面要比较常用的。
 
过滤器
描述
SecurityContextPersistenceFilter 
存储每一个请求来的上下文对象,在身份验证之前调用
LogoutFilter 
系统退出
UsernamePasswordAuthenticationFilter
执行系统登录的过滤器,用来验证用户名密码
DefaultLoginPageGeneratingFilter 
生成SS提供默认的登陆页面
SecurityContextHolderAwareRequestFilter 
对容器的servlet进行包装,重新请求
AnonymousAuthenticationFilter 
对SS的任何访问都要进行认证资源的初始化
FilterSecurityInterceptor
经过SS验证后访问认证地址前的拦截器
 
3、认证授权
       走到这里就很容易能想到,一个URL 要访问受保护的资源,那么可以反过来说这个URL 是要被许可,被认证的。那么在SS 中以用户                       登录成功为准则,保存用户登录信息到SS中作为凭证,再是对要访问的资源进行校验来做到认证的可靠性。
 
        SS中默认的授权方式是在SecurityContextPersistenceFilter过滤器拦截后创建系统认证对象,并传递到AnonymousAuthenticationFilter 过滤器进行认证对象数据的初始化值。到了这一步就相当于系统已经有了一个认证授权的对象。
       
  4、访问授权
        经过认证授权后,请求带着认真对象一并到了访问授权这步骤 AccessDecisionManager 决定如何对URL进行访问处理,FilterInvocationSecurityMetadataSource 已经存储了该URL对应的默认的权限资源。
 如果请求的URL 是一个登陆处理 “/login” 
在访问决定策略器决定处理期之前,会被UsernamePasswordAuthenticationFilter 拦截下来,看名字就知道是用户名和密码的认证过滤器
在过滤器中进行用户名和密码的验证,并把改用户名和密码组成的token存入认证对象AuthenticationManager管理器中。AuthenticationManager随后调用
this.getAuthenticationManager().authenticate(token);
意思是让认证管理器的认证方法去校验,即调用了UserDetail方法,查找权限,并返回一个User对象(SS自带的User对象)
同时在SS上下文中会存储这个认证后的对象,再进行AccessDecisionManager 的决定认证,首先会把认证用户的权限给取出来,然后再系统中预加载的URL对应的权限集合加载出来一一比对,如果符合则放行,且上下文中已经是认证有效的。可以通过SS的一些JSP标签获取认证后的用户信息。
 
如果请求的URL是一个非登陆处理的 “/XXX"
不像登陆处理的先被UsernamePasswordAuthenticationFilter 拦截, 此时经过这条拦截器不做任何处理,到了访问决策处理器的处理。改处理会把该URL所对应的权限集合加载出来,然后已预加载的认证对象里的认证资源(权限,资源)进行比对,当比对不成功就表示访问是失败的,则抛出访问异常,这些访问异常会被抽象类的调用者AbstractSecurityInterceptor 这个拦截器所捕捉。进行一个异常的处理,这种异常SS当做是认证异常,那么会从SS系统预留的URL中加载出登录页面的URL,如果配置的是/xxx.jsp, 那么就会跳转到/xxx.jsp登陆页面要求输入用户名和密码去校验。
提交表单到过滤器,就执行了登陆处理的“/login”和 登陆处理的流程是一样的。
 
分享到:
评论

相关推荐

    Spring Security3 中文版 张卫滨 推荐

    根据给定的信息,我们可以从《Spring ...以上是对《Spring Security3 中文版》部分章节内容的详细解读,涵盖了Spring Security的基础概念、具体实现以及高级配置等多个方面,希望能为读者提供全面且深入的理解。

    SpringSecurity企业及认证全套开发资源.docx

    Spring Security 的源码解读是深入理解其工作原理的关键。通过对核心类如`WebSecurityConfigurerAdapter`、`SecurityFilterChain`等的分析,可以了解到Spring Security是如何通过配置来实现安全控制的。 - **`...

    我的SpringSecurity实践

    首先,源码分析是理解SpringSecurity工作原理的关键。SpringSecurity框架是模块化的,它包括了核心的安全组件,如ProviderManager用于管理认证提供者,FilterChainProxy用于配置过滤器链,以及RememberMeServices...

    spring security3中文文档

    - **退出是怎么实现的**:解析退出功能的工作原理。 - **Remember-me**: - **实现remember-me选项**:引导如何启用记住我功能。 - **Remember-me是怎样实现的**:深入探讨remember-me的内部机制。 - **Remember...

    acegi源码解读.txtacegi源码解读.txtacegi源码解读.txt

    而acegi,作为Spring Security早期的名字,其源码分析对于理解Spring Security的工作原理具有不可替代的价值。本文将深入解析acegi(即Spring Security)的核心组件及其实现机制。 #### acegi核心组件与工作流程 #...

    spring技术内幕-深入解析spring架构与设计原理

    本书旨在帮助读者全面理解Spring的内部工作原理,从而更好地应用和优化Spring框架在实际开发中的使用。 Spring是Java领域最广泛使用的轻量级应用程序框架之一,它提供了依赖注入、AOP(面向切面编程)、MVC(模型-...

    图书:Spring 安全3

    6. **记住我服务**:了解Remember Me服务的工作原理,以及如何安全地实现长期登录功能。 7. **安全管理**:学习如何处理未授权访问、会话管理、密码加密和哈希等安全问题。 8. **Spring Security与RESTful服务**:...

    spring3+hibernate3+spring3MVC框架解读

    《Spring3+Hibernate3+Spring3MVC框架解读》 在现代软件开发中,Spring、...理解它们的工作原理以及如何有效地利用它们,是提升开发技能和项目质量的关键。同时,也要时刻警惕潜在的异常情况,确保代码的健壮性。

    Spring Src

    标题“Spring Src”指的是Spring框架的源代码,这是一份重要的学习资料,特别是对于Java开发者而言,深入理解Spring的工作原理能提升开发技能。Spring是Java企业级应用开发中最广泛使用的框架,它以其依赖注入...

    javaspring的文档.zip

    7. **spring高级源码笔记.pdf**:这可能包含了对Spring框架源代码的深入解读,有助于理解Spring的工作原理,对于想要深入了解Spring的开发者非常有价值。 8. **廖雪峰 Java教程.pdf**:廖雪峰的Java教程是初学者的...

    Spring5高级编程第五版 英文版

    9. **源码解读**:部分章节可能涉及Spring框架的源码分析,帮助读者理解其内部工作原理,提高问题排查和性能优化的能力。 10. **PDF格式**:本书以PDF形式提供,方便读者在各种设备上阅读和检索,易于打印和保存。 ...

    精通spring2.x企业应用开发详解

    详细讲解Spring的Inversion of Control(控制反转)容器,包括Bean的生命周期、初始化、销毁过程以及Bean的装配方式,让读者深刻理解Spring容器的工作原理。 7. **Chapter 13:Spring Security** 本章介绍Spring ...

    Wrox.Beginning.Spring.2015

    本章介绍了Spring MVC的基本概念,包括控制器、视图解析器等核心组件的工作原理。此外,还讨论了如何处理HTTP请求、数据绑定、表单验证等实际应用场景中的问题。 ### 使用Spring进行JDBC数据访问 (Chapter 4) 本章...

    spring-cloud实战源码

    Spring Cloud Sleuth和Zipkin用于分布式追踪,Spring Cloud Security则为微服务提供安全防护。 总的来说,《Spring Cloud实战源码》涵盖了Spring Cloud的核心组件,从入门到进阶,再到源码解析,帮助开发者全面掌握...

    Spring Boot核心技术-笔记-pdf版.zip

    通过这份《Spring Boot核心技术-笔记-pdf版》的学习,你将能够深入理解Spring Boot的各个核心组件和它们的工作原理,从而更好地利用这个强大的框架来构建高效、稳定的Java应用程序。在阅读过程中,结合实际项目实践...

    Spring面试专题及答案整理文档.rar

    以上只是部分核心知识点,实际的《Spring面试专题及答案整理》文档可能还包含更多细节,如Spring的IoC容器原理、Spring Boot的自动配置机制、Spring Cloud的Eureka和Zuul等组件的用法等。通过深入学习和理解这些知识...

    spring面试题目以及答案集合

    重点理解@Transactional注解的工作原理,以及如何配置事务管理器。 7. **Spring JDBC和MyBatis整合**:Spring提供了JdbcTemplate和NamedParameterJdbcTemplate,简化数据库操作。MyBatis则提供了更灵活的SQL映射,...

    spring 源码解析

    《Spring源码解析》系列文章深入探讨了Spring框架的核心组件和工作原理,为读者提供了丰富的技术洞察。以下是对这些主题的详细解读: 1. **Spring MVC**:Spring MVC是Spring框架的一部分,它提供了构建Web应用程序...

Global site tag (gtag.js) - Google Analytics