[TOC] # 自定义uaa-client-spring-boot-starter uaa-client-spring-boot-starter深度扩展spring cloud oauth2/ spring security封装平台通用资源服务能力,进行token 权限校验。其作用是包装资源服务器,作为独立单元为api-gateway,user-center等提供安全保障 ## pom依赖 ![](https://img.kancloud.cn/d4/3b/d43ba51edb494003fbf44e35c5792578_1496x924.png) ## Spring Security Oauth 认证授权介绍 ### 基本设计 ![](https://img.kancloud.cn/28/18/281868d3d6f64df665978bf3229327d1_1101x517.png) ### 常用过滤器 ![](https://img.kancloud.cn/74/de/74de7856c4d3e3029b52eeb10941a822_1793x901.png) * 访问者(Accessor)需要访问某个资源(Resource)是这个场景最原始的需求,但并不是谁都可以访问资源,也不是任何资源都允许任何人来访问,所以中间我们要加入一些检查和防护 * 在访问资源的所经之路上,可能遇到细菌,病毒,不管怎么样,对于要防护的资源来说最好的方法就是设关卡点,对于上图的FilterSecurityInvation,MethodIncation,Jointpoint,这些在spring security oauth中统称SecuredObjects * 我们知道在哪里设置关卡点最合适,下一步就是设置关卡,对应FileSecurityInterceptor,MethodSecurityInterceptor,AspectSecurityInterceptor, 这些关卡统一的抽象类是AbstractSecurityInterceptor * 有关卡点,关卡了以后,到底谁该拦截谁不应该呢,spring security oauth中由 AccessDecisionManager控制 * 最后一个问题,这个谁怎么定义,我们总得知道当前这个访问者是谁才能告诉AccessDecisionManager拦截还是放行,在spring security oauth框架中AuthenticationManager将解决访问者身份认证问题,只有确定你在册了,才可以给授权访问。AuthenticationManager,AccessDecisionManager,AbstractSecurityInterceptor属于spring security框架的基础铁三角。 * 有了以上骨架,真正执行防护任务的其实是SecurityFilterChain中定于的一系列Filter,其中ExceptionTranslationFilter,它负责接待或者送客,如果访问者来访,对方没有报上名来,那么,它就会让访客去登记认证(找AuthenticationManager做认证),如果对方报上名了,但认证失败,那么请重新认证送客,送客的方式是抛出相应的Exception,所以名字叫做ExceptionTranslationFilter。 * 最后,这个filter序列中可能不满足我们的需求,比如增加验证码,所以我们需要在其中穿插自己的Filter实现类,为定制和扩展Spring Security Oauth的防护体系。 * spring security内置的filter序列 ### 执行过滤链 ![](https://img.kancloud.cn/18/fe/18fe52e694ccccf09a6d9594d6ea788a_1270x348.png) ## 认证授权服务器处理流程 ![](https://img.kancloud.cn/e1/6a/e16a2ecf59a3b2c9b94a6b2f1c0de2ef_1111x632.png) ## 授权类处理流程图 ![](https://img.kancloud.cn/3e/23/3e234e7710733533e20624b8ad577f52_2025x719.png) ## 功能 * 通用资源服务器校验 * 通用的token校验机制(TokenStore) * 通用的访问控制(OpenAuthorizeConfigManager) * 通用的异常配置(SecurityHandlerConfig,ExceptionHandlerAdvice) ### 资源服务器 * 要访问资源服务器受保护的资源需要携带令牌(从授权服务器获得) * 客户端往往同时也是一个资源服务器,各个服务之间的通信(访问需要权限的资源)时需携带访问令牌 * @EnableResourceServer引入OAuth2AuthenticationProcessingFilter过滤器 ![](https://img.kancloud.cn/8f/d8/8fd81c3e5e8ac3fda50aa7201684de39_2475x1096.png) * 通过继承 ResourceServerConfigurerAdapter 类来配置资源服务器 ![](https://img.kancloud.cn/f6/75/f6757b5772312b3e9f411f95f09cb461_2276x1104.png) ### ResourceServerSecurityConfigurer 可配置属性 * tokenServices:ResourceServerTokenServices 类的实例,用来实现令牌业务逻辑服务 * resourceId:这个资源服务的ID,这个属性是可选的,但是推荐设置并在授权服务中进行验证 * tokenExtractor 令牌提取器用来提取请求中的令牌 * 请求匹配器,用来设置需要进行保护的资源路径,默认的情况下是受保护资源服务的全部路径 * 受保护资源的访问规则,默认的规则是简单的身份验证(plain authenticated) * 其他的自定义权限保护规则通过 HttpSecurity 来进行配置 * 使用 DefaultTokenServices 在资源服务器本地配置令牌存储、解码、解析方式 ## 核心代码处理逻辑 认证授权核心的逻辑在于票据的生成和验证,认证服务器负责生成票据,资源服务器负载验证票据,二者统一调用DefaultTokenServices服务。 ![](https://img.kancloud.cn/6d/59/6d5984fccaca417aded4e24e4d483301_1402x589.png) ### DefaultTokenServices票据服务 DefaultTokenServices核心服务在于调用TokenStore生成验证token ![](https://img.kancloud.cn/eb/91/eb911f3fb4880686730ef6f31d126507_2134x891.png) #### 票据token redis持久化 ![](https://img.kancloud.cn/db/d0/dbd0ebe9dac4d5e17b168bd36adcf1f0_2097x854.png) #### redis token 结构 ~~~ 排除refresh_token,主要key如下: * access:token值,value为string,这个主要是通过token值来获取OAuth2AccessToken * auth:token值,value为string结构,这个主要用来获取token的OAuth2Authentication,用来获取相应的权限信息 * auth_to_access:OAuth2Authentication相关信息加密后的值,value为string结构 这个主要是通过OAuth2Authentication来获取OAuth2AccessToken * client_id_to_access:clientId,value为list结构 这个主要是存储了每个clientId申请的OAuth2AccessToken的集合方便用来审计和应急处理跟clientId相关的token * uname_to_access:clientId:userId,value的结构是list,存储OAuth2AccessToken的集合 主要是为了通过clientId,userId来获取OAuth2AccessToken集合,方便用来获取及revoke approval ~~~ #### 票据token jwt存储 ![](https://img.kancloud.cn/0f/35/0f3586968b9525f4239685031d776a6f_2470x1086.png) ## com.open.capacity.uaa.common.UAAClientAutoConfig的作用 * 提供OAuth2AuthenticationProcessingFilter保护我们的API接口 * 提供白名单免除OAuth2AuthenticationProcessingFilter校验API接口 * 提供方法级权限校验 ### 资源服务器核心配置 ![](https://img.kancloud.cn/b4/45/b445f86a859fa26cedfa5aedb4a9fe70_2303x1198.png) 通过以上配置可以达到以下效果 * 不带token http://127.0.0.1:7000/users?page=1&limit=10 ![](https://img.kancloud.cn/87/63/8763013095dc8276f4a829ae662ba8b8_2082x437.png) * 带不合法token http://127.0.0.1:7000/users?access_token=sds&page=1&limit=10 ![](https://img.kancloud.cn/cf/27/cf2767eeaa4b69893390039a6fa3dd93_1535x182.png) * 带合法token http://127.0.0.1:7000/users?access_token=a3e3b8b3-5014-4eb5-b62e-6261f8afe4b5&page=1&limit=10 ![](https://img.kancloud.cn/bb/2d/bb2dac215543ca02b2a2e6641df24730_2560x383.png) [查看token的生成](10.%E8%87%AA%E5%AE%9A%E4%B9%89uaa-server-spring-boot-starter.md) ### 资源服务器核心权限过滤 ![](https://img.kancloud.cn/28/cf/28cfe2a0b8673ec889a8076a21351036_2445x946.png) ### 自定义安全门面设计 ![](https://img.kancloud.cn/1f/6a/1f6aa5c31edc185578ff6faf2956f7d7_2462x1031.png) ### 自定义安全策略 ![](https://img.kancloud.cn/7a/d3/7ad37669f8a7c0eb99590f19d0babbde_2484x1187.png) ### 白名单配置类 ![](https://img.kancloud.cn/4f/21/4f2129dfc88717d199b02faa9c85e586_2085x1212.png) ### 白名单配置文件 ![](https://img.kancloud.cn/c3/6e/c36e7ab5a4a35f86afb578931af7446c_2404x1129.png) ### websocket安全拦截 ![](https://img.kancloud.cn/e8/37/e8376e5c66db82cd64dc6376eab5e66d_2439x1208.png) ### 获取当前登录人 ![](https://img.kancloud.cn/8f/78/8f787452a7ffa21f68f238c2916d86e3_2131x896.png) ``` @GetMapping("/users/current") @ApiOperation(value = "根据access_token当前登录用户") public ResponseEntity<LoginAppUser> getLoginAppUser(@LoginUser(isFull = true) SysUser user) { return ResponseEntity.succeed(sysUserService.getLoginAppUser(user)); } ``` * 传入token方式可以配合@LoginUser方式获取当前登录人 * 传入userId username role的方式也可以配合@LoginUser方式获取当前登录人