Spring Security总结(一)

请注意,本文编写于  1,011  天前,最后编辑于  1,002  天前,内容可能已经不具有时效性,请谨慎参考。

Spring Security总结(一)概述

之前一个后台项目以spring boot框架开发,是以前后端分离形式开发,因此为了权限验证,引入了spring security,现在在此将用到过的功能记录下来,以供参考

一、实现功能

  • 角色权限验证与控制
  • jwt Token验证
  • redis缓存
  • 用户自动登录
  • 静态资源映射
  • 用户登录处理

二、Spring Security概述

目前java项目常用权限控制的就是shiro以及spring security,这两种权限控制的方式都在spring上得到了很好的支持,但是采用spring boot进行开发后,对spring security进行了很好的集成,提供了自动化的配置方案,因此是个非常好的选择

什么是Spring Security

Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架
功能:

  • 它具有全面的并且可扩展的身份验证和授权系统
  • 可以防止会话固定,点击劫持,跨站点请求伪造等攻击
  • 集成了servlet API
  • …etc.

工作流程

下图为Spring Security主要工作流程
image.png
一个请求需要通过以下的认证链后决定该请求能否通过验证,正常访问我们的服务器

几个重要组成部分

1. SecurityContextHolder

SecurityContextHolder 是最基本的对象,它负责存储当前安全上下文信息。即保存着当前用户是什么,是否已经通过认证,拥有哪些权限,比如会将Authentication保存在上下文中
SecurityContextHolder默认使用ThreadLocal策略来存储认证信息,意味着这是一种与线程绑定的策略。

2. Authentication

image.png

Authentication是一个接口,提供几个关于认证的方法

  • UsernamePasswordAuthenticationToken: 而这个类是Authentication的一个* 常用的实现类,用来进行用户名和密码的认证
  • getAuthorities: 权限列表,通常是代表权限的字符串列表;
  • getCredentials: 密码信息,由用户输入的密码凭证,认证之后会移出,来保证安全性;
  • getDetails: 细节信息,Web应用中一般是访问者的ip地址和sessionId;
  • getPrincipal: 最重要的身份信息,一般返回UserDetails的实现类;

3. UserDetails

image.png
UserDetails是一个接口,提供了getPassword()和getUsername()方法

  • getPassword: 获得密码
  • getUsername: 获得用户名
    可以看到Authentication和UserDetails都有获得密码得方法,而区别就是Authentication中的getCredentials来源于用户提交的密码凭证,而UserDetails中的getPassword取到的则是用户正确的密码信息,认证的第一步就是比较两者是否相同,除此之外,Authentication中的getAuthorities是认证用户名和密码成功之后,由UserDetails中的getAuthorities传递而来。而Authentication中的getDetails信息是经过了AuthenticationProvider认证之后填充的。

4. UserDetailsService

UserDetailsService 只有一个方法loadUserByUsername,就是从特定的地方(一般是从数据库中)加载用户信息

Filters

1. SecurityContextPersistenceFilter

SecurityContextPersistenceFilter的两个主要作用便是请求来临时创建SecurityContext安全上下文信息和请求结束时清空SecurityContextHolder

在 Web 应用中这是通过 SecurityContextPersistentFilter 实现的,默认情况下其会在每次请求开始的时候从 session 中获取 SecurityContext,然后把它设置给 SecurityContextHolder,在请求结束后又会将 SecurityContextHolder 所持有的 SecurityContext 保存在 session 中,并且清除 SecurityContextHolder 所持有的 SecurityContext。这样当我们第一次访问系统的时候,SecurityContextHolder 所持有的 SecurityContext 肯定是空的,待我们登录成功后,SecurityContextHolder 所持有的 SecurityContext 就不是空的了,且包含有认证成功的 Authentication 对象,待请求结束后我们就会将 SecurityContext 存在 session 中,等到下次请求的时候就可以从 session 中获取到该 SecurityContext 并把它赋予给 SecurityContextHolder 了,由于 SecurityContextHolder 已经持有认证过的 Authentication 对象了,所以下次访问的时候也就不再需要进行登录认证了。

2. UsernamePasswordAuthenticationFilter

用于处理来自表单提交的认证。
image.png
参看其中的源码可以知道,整个流程主要就是调用了authenticationManager完成认证,根据认证结果执行successfulAuthentication或者unsuccessfulAuthentication,无论成功失败,一般的实现都是转发或者重定向等处理。

3. authenticationManager

AuthenticationManager接口只包含一个方法,那就是认证,它是认证相关的核心接口,也是发起认证的出发点。它通过不同的provider实现来进行不同的认证,它提供了默认的认证方式,也可以进行自定义的认证方式
image.png
上图便是其认证过程
各个类之间的关系便是如下所示
image.png

4. FilterSecurityInterceptor

FilterSecurityInterceptor主要功能就是鉴权,判断用户是否有权限访问资源。需要一个AccessDecisionManager和一个AuthenticationManager的引用。它会从SecurityContextHolder获取Authentication,然后通过SecurityMetadataSource可以得知当前请求是否在请求受保护的资源。

无状态的应用

无状态可以减轻服务器压力,并且可扩展性较好,而spring security也可以做无状态下的权限认证,一般现在的做法是通过token认证的方式实现用户的认证,通过用户每次携带token的请求,来判断用户的认证权限,而这个判断的过程就可以通过一个自定义的filter,然后添加到filter链中来实现