SpringCloud+Spring Security+OAuth2 + JWT + Gateway讲解

项目简介

  • 本登录系统是一个适应前后端分离并支持传统PC登录的全方位微服务登录架构
  • 基于Spring Boot 2.2.8.、 Spring Cloud Hoxton.SR5 和 Spring Cloud Alibaba 2.2.1
  • 深度定制Spring Security,基于RBAC、jwt和oauth2的无状态统一权限认证的
  • 单点登录、单点登出、续签等功能
  • 提供C端多租户功能
  • 提供第三方被授权登录方式(openId方式)
  • 提供供内部服务调用的OAuth2客户端模式
  • 提供基于OAuth2的第三方授权码模式
  • 提供自定义添加OAuth2的四种模式的扩展
  • 统一角色权限校验

实现思路

1.基于Spring Security源码

Spring Security过滤器链

所有的请求首先会到 AbstractAuthenticationProcessingFilter 中,并调用doFilter方法,该过滤器会判断用户是否需要登录,如果不登录直接返回。如果需要登录,则调用attemptAuthentication判断自定义拦截器,如果存在自定义拦截器,则会调用子类的该方法,用于用户名、密码登录。否则会进UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter 主要负责登录请求(包含表单等),请求首先回到 attemptAuthentication 方法中,判断用户名和密码是否是空,如果不是,就去构建 UsernamePasswordAuthenticationToken 对象。

UsernamePasswordAuthenticationToken 是 Authentication 接口的其中一个实现,如果第一次进入(这时还没有执行权限认证),该构造方法首先会把用户名、密码设置到本地,然后会赋予权限一个空权限,然后会 setAuthenticated,因为这时还没有执行权限,所以会设置为false。

然后回到 UsernamePasswordAuthenticationFilter ,执行了 setDetails 方法,把request信息和 UsernamePasswordAuthenticationToken 对象塞入进去。

UsernamePasswordAuthenticationFilter 最后一步会进去 AuthenticationManager(也就是如上图第二步所示),它本身没什么作用,主要用来管理多个AuthenticationProvider,因为本身登录方式有多种,比如用户名密码登录,第三方登录等区别,并判断当前请求是否支持当前AuthenticationProvider,如果支持,则执行真正的校验逻辑,会调用 authenticate 方法,该方法默认从AbstractUserDetailsAuthenticationProvider 实现,该类的 authenticate 方法会调用 retrieveUser 方式,该方式是一个抽象方法,由 DaoAuthenticationProvider 实现。

划重点:真正的校验逻辑就在这个方法内,而最终会拿到 getUserDetailsService的loadUserByUsername方法,这个方法就是我们自己程序要实现的用户校验逻辑

在上步拿到UserDetails后,AbstractUserDetailsAuthenticationProvider 把拿到的UserDetails校验,调用preAuthenticationChecks.check(UserDetails)方法,会进行一些预检查,会判断用户是否锁定,是否过期等操作。在做完预检查后,会调用additionalAuthenticationChecks 进行一些附加检查,该方法是一个抽象类,由DaoAuthenticationProvider 实现,主要是对密码的校验(PasswordEncoder)。上面检查都做完后,return this.createSuccessAuthentication(),至此,整个AbstractUserDetailsAuthenticationProvider 认证流程走完。

上面说到 createSuccessAuthentication(),该方法会重新(重点:记住是重新构造UsernamePasswordAuthenticationToken,上面调过一次)构造UsernamePasswordAuthenticationToken方法,把username、password和权限重新塞回去。

至此,整个调用链结束,然后Authentication会沿着刚才的调用链返回回去,然后又回到 UsernamePasswordAuthenticationFilter,拿到用户名、密码那。最终回到最开始的 AbstractAuthenticationProcessingFilter 过滤器 ,AbstractAuthenticationProcessingFilter.doFilter 成功结束return

PS:this.successfulAuthentication(request, response, chain, authResult),该方法会调用我们自定义的successfulHandler处理器(重点:在OAuth2中,会接手successfulHandler,然后返回token,因此在OAuth2不需要写该handler),successfulAuthentication 方法会把登录成功用户信息存到ThreadLocal中,全局共享。

PS:上面所有流程中任何一处出现错误或者异常则会掉unsuccessfulAuthentication方法,该方法会调用自定义的failureHandler把存入的用户信息从ThreadLocal中清除。

2.Security多请求共享

session共享

如上图所示,其实上面最后一步在 successfulAuthenticationunsuccessfulAuthentication 就能看到 SecurityContext,它的作用是把 Authentication 包装起来,而 SecurityContextHolder 则是一个ThreadLocal封装,封装 SecurityContext

security过滤器链

SecurityContextPersistenceFilter 是过滤链上第一个过滤器,所有请求都先过它,响应最后过它,它的作用是:
请求过来后,检查session,判断session是否有
SecurityContext,如果有就把SecurityContext拿出来放到线程里;当整个响应回来最后一个过它的时候,它检查线程,如果线程里有SecurityContext,就拿出来放到Session里,因为整个响应过程是在一个线程里的,在线程其他位置随时可以拿到用户信息。

Oauth2.0

客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)

OAuth 2.0定义了四种授权方式:
  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

而它默认的授权服务接口是:

/oauth/authorize:验证接口, AuthorizationEndpoint
/oauth/token:获取token
/oauth/confirm_access:用户授权
/oauth/error:认证失败
/oauth/check_token:资源服务器用来校验token
/oauth/token_key:jwt模式下获取公钥;位于:TokenKeyEndpoint ,通过 JwtAccessTokenConverter 访问key

JWT

简述

客户端身份经过服务器验证通过后,会生成带有签名的 JSON 对象并将它返回给客户端。客户端在收到这个 JSON 对象后存储起来。

在以后的请求中客户端将 JSON 对象连同请求内容一起发送给服务器,服务器收到请求后通过 JSON 对象标识用户,如果验证不通过则不返回请求的数据。

验证不通过的情况有很多,比如签名不正确、无权限等。在 JWT 中服务器不保存任何会话数据,使得服务器更加容易扩展。

Base64URL 算法

在讲解 JWT 的组成结构前我们先来讲解一下 Base64URL 算法。这个算法和 Base64 算法类似,但是有一点区别。

我们通过名字可以得知这个算法使用于 URL 的,因此它将 Base64 中的 + 、 / 、 = 三个字符替换成了 - 、 _ ,删除掉了 = 。因为这个三个字符在 URL 中有特殊含义。

JWT 组成结构

JWT 是由三段字符串和两个 . 组成,每个字符串和字符串之间没有换行(类似于这样:xxxxxx.yyyyyy.zzzzzz),每个字符串代表了不同的功能,我们将这三个字符串的功能按顺序列出来并讲解:

1. JWT 头

JWT 头描述了 JWT 元数据,是一个 JSON 对象,它的格式如下:

json{“alg”:“HS2

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值