任何的流程必须通过语言能够描述,才达到最终效果

认证和授权总流程

在这里插入图片描述
AnonymousAuthenticationFilter在所有认证过滤器最后,判断SpringSecurityConetxt中是否存在Authentication,若不存在则设置一个AnonymousAuthentication。

认证技术技术选型

企业中大多使用Shiro框架和Spring Security进行用户身份认证,而实现SSO的技术选型又有Spring Security Oauth2.0和CAS,它们都可以很好的实现单点登录,我对Oauth2.0比较推介,因为它不仅在现有框架Spring Security下进行很好的实现,而且与其他技术的兼容性比较好,最重要的是Spring Cloud对它有现成的实现,搭建微服务认证中心非常合适。而CAS代码实现是是通过一些零散的过滤器实现,而且对前后端分离不好实现。

CAS对各个子系统的资源请求进行认证处理,类似于Oauth2.0基于授权码的授权模式,客户端应用不接触用户的账号密码信息,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。而Oauth2.0提供的账号密码授权模式客户端应用是接触到用户的安全信息的,但只适合对APP的认证处理。当用户再次请求时,它们都需要通过认证中心验证令牌的有效性,但是基于JWT的oauth2.0协议可以在令牌中取出用户信息即可,省去了再次验证信息

具体来讲,有单机版的认证,多机版的认证,基于微服务的认证。
单机版的认证可以通过框架直接完成
多机版的认证可以通过Spring Security整合Oauth2.0协议,也可以整合CAS来实现,也可使用CAS单独实现
微服务的认证其实就是基于网关的认证和授权,所有对微服务的请求都通过网关进行细粒度的控制,通过认证中心进行实际的认证和授权,网关除了解决认证和授权,还进行日志收集和熔断限流

cas基本流程

https://blog.csdn.net/anumbrella/category_7765386.html
在这里插入图片描述

首次登陆流程

  1. 首先用户访问系统1受保护的资源,系统1发现未登陆,跳转至SSO认证中心
  2. SSO认证中心发现用户未登录,将用户引导至登录页面
  3. 用户输入用户名和密码提交至SSO认证中心
  4. SSO认证中心校验用户信息,创建用户与SSO认证中心之间的会全局会话,同时创建授权令牌
  5. SSO认证中心带着令牌跳转回最初的请求地址(系统1)
  6. 系统1拿到令牌,去SSO认证中心校验令牌是否有效
  7. SSO认证中心校验令牌,返回有效,注册系统1的地址
  8. 系统1使用该令牌创建与用户的会话,称为局部会话,返回给用户受保护资源

再次登陆流程

  1. 用户访问系统2受保护的资源
  2. 系统2发现用户未登录,跳转至SSO认证中心,并将自己的地址作为参数传递过去
  3. SSO认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
  4. 系统2拿到令牌,去SSO认证中心校验令牌是否有效
  5. SSO认证中心校验令牌,返回有效,注册系统2地址
  6. 系统2使用该令牌创建与用户的局部会话,返回给用户受保护资源

注销流程

  1. 系统1根据用户与系统1建立的会话id拿到令牌,向SSO认证中心发起注销请求
  2. SSO认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址
  3. SSO认证中心向所有注册系统发起注销请求
  4. 各注册系统接收SSO认证中心的注销请求,销毁局部会话
  5. SSO认证中心引导用户至登录页面

TGC:用户持有的令牌,表示成功登陆casClient web应用
TGT:CAS为用户签发的全局令牌,构建全局会话
ST(TGT签发):TGT签发的某服务的令牌,构建局部会话
ST是TGT签发的。用户在CAS上认证成功后生成TGT,然后用TGT签发一个ST,ST包含TGT属性,然后redirect到客户端应用

引入app的代理,为用户去申请PT,PT代表用户成功登陆casClient app应用
a) PGT(ST签发):代理服务持有的令牌,表示用户成功登陆某一代理服务,可以代理应用为其申请PT
b) PT:CAS为用户签发的访问app服务的令牌,表示成功登陆casClient app应用

cas实现相关

如果要验证其他信息,比如邮箱,手机号,但是邮箱,手机信息在另一个数据库,还有在一段时间内同一IP输入错误次数限制等。这里就需要我们自定义认证策略,自定义CAS的web认证流程
通过拦截请求获取到Handler,来实现自定义认证策略

自定义登陆逻辑

  1. 通过继承AbstractUsernamePasswordAuthenticationHandler实现用户名密码登陆,或者AbstractPreAndPostProcessingAuthenticationHandler实现其他数据的处理逻辑
  2. 通过继承AuthenticationEventExecutionPlanConfigurer注册自定义的认证逻辑

cas service配置

  1. 配置内容主要是:服务访问配置,服务属性配置,服务到期策略配置
  2. 配置存储主要是:JSON file,Redis,JPA

cas service管理

  1. 启用线程项目cas-management-overlay进行服务管理
  2. 自定义服务管理程序,通过实现ServiceManager接口

自定义用户登陆界面

认证登陆页面耦合于cas server

  1. 根据配置的cas service存储方式,覆盖默认的登陆界面
  2. 自定义验证码,使用Google的kaptcha类

SpringBoot配置cas client

  1. 配置拦截请求和退出的路径,并注入自定义配置类
  2. 注入FilterRegistrationBean,然后通过它配置登陆认证过滤器,登出过滤器,ticket效验过滤器,获取登陆信息

SpringSecurity基本流程

认证流程

认证请求到达SecurityContextPersistenceFilter检查是否有session,若有则直接返回登陆成功,否则进入UsernamePasswordFilter进行账号密码认证,它底层通过AuthenticationManager遍历可用的AuthentcationProvider进行具体的认证操作,底层通过UserDetailsService根据用户名称获取用户信息与表单填入的进行匹配,若认证成功则将用户信息放SecurityContextHolder

实现remember功能

UsernamePasswordAuthenticationFilter认证成功后,在成功处理器就会自动调用RememberMeService的方法创建token和用户名一起存储到数据库中,然后将token写到浏览器的Cookie中。
当用户再次访问系统时,被RememberMeAuthenticationFilter过滤器所拦截,它读取cookie中的token,通过RememberService从数据库中查出token对应的用户名,然后通过UserDetailService再根据用户名查询用户信息,最后放到SecuritContext里。
在这里插入图片描述

图形验证码效验

  1. 自定义控制器生成图形验证码,并生成图片返回前端,然后将其保存到redis和session中
  2. 创建验证码过滤器,判断用户填写的验证码和系统生成的验证码是否匹配,若不匹配则抛异常

短信验证码登陆效验

  1. 自定义控制器生成短信验证码,将其发送给用户,将验证码保存到redis或者session中
  2. 自定义过滤器拦截短信登陆请求,然后自定义AuthenticationProvider返回已认证Authentication
  3. 自定义短信验证码过滤器,判断用户填写的短信验证码和存储中的短信验证吗是否匹配,若不匹配则抛异常
    |——为何不在provider进行匹配短信验证码呢??为了使的验证短信验证码这个流程可以复用,比如让支付流程调用等
    |——有两条线,一条是根据手机号进行身份认证(只保证系统中存在此用户),另一条是验证短信验证码是否匹配的逻辑

使用SpringSocial实现第三方登陆

  1. 用户访问客户端前端,浏览器将请求导向认证服务器进行认证
  2. 用户同意授权,携带授权码返回给客户端前端
  3. 客户端后台携带授权码申请令牌
  4. 认证服务器发放令牌,客户端后台访问服务提供商的用户数据,携带令牌返回客户端前端

Oauth2.0实现认证服务器

相比CAS,第三方

  1. Oauth生成令牌流程(认证服务器)
    客户端应用向认证服务器申请令牌,TokenEndpoint通过ClientDetailsService从存储中获取注册的第三方应用信息,然后将第三方用户信息和用户请求信息封装为Oauth2Authentication,AuthorizationServerTokenService创建Oatuth2AccessToken令牌,然后TokenStore将其存到某存储器中
  2. Oauth效验令牌流程(资源服务器)
    客户端携带令牌访问请求到达Oauth2AuthenticationProcessFilter,tokenExtractor从request中获取Authentication,OAuth2AuthenticationManager通过tokenService查询token对应的OAuth2Authentication对应,若登陆成功将Authentication放到SpringSecurityConetxt中。

Oauth2.0重构用户名密码登陆

在成功处理器中,封装Oauth2Authentication,然后AuthorizationServerTokenService创建Oatuth2AccessToken令牌,然后TokenStore将其存到某存储器中
在这里插入图片描述

基于Oauth2.0 jwt实现SSO

在这里插入图片描述

  1. 创建认证服务器,配置认证服务器客户端信息,配置token存储策略,配置tokenkey需要身份认证
  2. 创建rest服务器1,@EnableOauth2Sso,配置客户端配置(客户端信息,访问认证服务器url,请求令牌url,获取密钥url)
  3. 创建rest服务器2,@EnableOauth2Sso,配置客户端配置(客户端信息,访问认证服务器url,请求令牌url,获取密钥url)

Session管理

  1. session超时处理:server.session.timeout= 最少一分钟,可配置失效处理控制器
  2. session并发控制
    用户在其他浏览器登陆,踢掉前面那个:maximumSession(1)
    用户不允许在其他地方登陆:maxSessionPreventLogin(true)
  3. 集群session处理
    spring.session.store-type=REDIS
  4. 退出登陆
    访问/logout后,当前session失效,清空remember-me记录,清空securityConetxt,重定向到登录页
    logoutUrl()配置退出控制器,logoutSuccessHandler()配置退出重定向url,deleteCookies()删除浏览器cookies

授权

系统配置信息:权限规则基本不变,antMatchers(方法,路由).hasRole(角色)
用户权限信息 :权限规则灵活变化

SpringSecurity授权源码流程

在这里插入图片描述
请求信息vs系统配置权限vs用户拥有的权限——>AccessDecisionManager(策略)——>AccessDecisionVoter(WebExpressionVoter)多个投票者进行投票
SpringSecurity将权限转换成一个权限表达式,然后通过WebExpressionVoter进行评估,只要有一个通过就通过
在这里插入图片描述
连用表达式
在这里插入图片描述

基于配置文件进行权限控制

  1. 只区分是否登录or只区分简单角色
  2. 权限规则基本不变

问题:在使用配置文件配置权限时,安全模块事先并不知道业务模块具体有哪些API需要权限控制,怎么将配置信息进行全局管理呢???
在这里插入图片描述
AuthorizeConfigManager收集所有AuthorizeConfigProvider的实现,然后进行统一配置
在这里插入图片描述

基于角色的权限控制

角色众多,随着公司发展权限不断变化

资源表(开发人员维护):菜单,按钮及其URL
用户表,角色表,用户-角色表,角色-权限表
.access("@rbacService.hasPermission(request,authentication)")
.access("#rbacService.hasPermission(request,authentication)") //需要配置相应的权限表达式处理器

怎样对接自己写的权限模块 和 SpringSecurity
a)定义一个RbacService接口,根据request和Authentication判断是否有权限
b)实现授权服务方法,根据用户名查询所拥有权限的所有URL,只要有一个匹配request.getRequestURI()就判定权限通过
c)实现AuthorizeConfigProvider,将自己自定义的权限服务,以表达式的方式配置进去
d) 实现一个AuthorizeConfigManager,注入所有模块的AuthorizeConfigProvider,然后将授权配置管理器配置到SecurityCofig默认配置

微服务环境基于网关的认证和授权

在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐