Security对接 sso服务总结——思路篇

功能

  1. 自定义登录线便于Oauth2登录服务出错时使用
  2. 自定义认证校验(授权对象存于redis,实现分布式认证)
  3. oauth2授权服务整合
  4. oauth2资源服务整合

代码地址

架构

  1. language:java
  2. framework:springframework + projectreactor + thymeleaf + webjars
  3. Build Tools:gradle

启动

  1. 拉取oauth2单点代码:https://gitee.com/jdw-silky/silky-sso-server.git
  2. 依次启动oauth2授权服务,oauth2资源服务

总结————思路篇

自定义登录实现逻辑

  1. 配置了自定义登录拦截器,
    拦截登录请求生成有效Authentication放入security上下文,redis保存 登录标识——Authentication

  2. 配置了自定义登录校验拦截器
    拦截带有登录标识的请求,通过该标识从redis获取Authentication,获取不到则代表redis已退出,清理security上下文

  3. 将这两个拦截器放到security拦截器链路中,FilterChainProxy

自定义登录+自定义授权实现逻辑

  1. 配置了自定义登录拦截器,
    拦截登录请求生成有效Authentication放入security上下文,redis保存 登录标识——Authentication
  2. 配置了自定义登录校验拦截器
    拦截带有登录标识的请求,通过该标识从redis获取Authentication,获取不到则代表redis已退出,清理security上下文
  3. 自定义访问决策处理器AccessDecisionProcessor,与默认的WebExpressionVoter构建访问决策管理器AccessDecisionManager
  4. 将新构建的访问决策管理器放入security配置中
  5. 将这两个拦截器放到security拦截器链路中,FilterChainProxy

自定义登录+自定义授权+Oauth2客户端登录授权+Oauth2资源服务实现逻辑

需求
自定义登录保留
未登录访问限制资源默认跳转Oauth2登录页面
Oauth2登录回来后需要达到与自定义登录一样的效果

登录授权

  1. 配置了自定义登录拦截器:拦截自定义登录请求生成有效Authentication放入security上下文,redis保存 登录标识——Authentication
  2. 配置了自定义登录校验拦截器:拦截带有登录标识的请求,通过该标识从redis获取Authentication,获取不到则代表redis已退出,清理security上下文
  3. 自定义访问决策处理器AccessDecisionProcessor,与默认的WebExpressionVoter构建访问决策管理器AccessDecisionManager
  4. 将新构建的访问决策管理器放入security配置中
  5. 将这两个拦截器放到security拦截器链路中,FilterChainProxy
  6. security开始Oauth2登录配置
  7. Oauth2登录添加自定义登录成功处理器,开启Oauth2登录
  8. 在Oauth2登录成功后,添加自定义登录成功处理器。进行自定义认证逻辑,合并自定义授权与Oauth2授权等操作

Oauth2服务整合

  1. 配置spring.security.oauth2.client.provider地址,该地址拼接/.well-known/openid-configuration组成实际Oauth2对接相关信息获取地址
{
   "issuer": "http://192.168.137.139:9000",
   "authorization_endpoint": "http://192.168.137.139:9000/oauth2/authorize",
   "token_endpoint": "http://192.168.137.139:9000/oauth2/token",
   "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"],
   "jwks_uri": "http://192.168.137.139:9000/oauth2/jwks",
   "response_types_supported": ["code"],
   "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"],
   "subject_types_supported": ["public"],
   "id_token_signing_alg_values_supported": ["RS256"],
   "scopes_supported": ["openid"]
}
  1. 为向Oauth2资源服务发起的请求添加Oauth2授权,此处重点就是确保授权码默认认证获得的Oauth2授权

    @GetMapping(value = "/authorize", params = "grant_type=authorization_code")
    public String authorizationCodeGrant(Model model,
                                         @RegisteredOAuth2AuthorizedClient("messaging-client-authorization-code")
                                                 OAuth2AuthorizedClient authorizedClient) {

        String[] messages = this.webClient
                .get()
                .uri(this.messagesBaseUri)
                .attributes(oauth2AuthorizedClient(authorizedClient))
                .retrieve()
                .bodyToMono(String[].class)
                .block();
        model.addAttribute("messages", messages);

        return "index";
    }

    @GetMapping(value = "/authorize", params = "grant_type=client_credentials")
    public String clientCredentialsGrant(Model model) {

        String[] messages = this.webClient
                .get()
                .uri(this.messagesBaseUri)
                .attributes(clientRegistrationId("messaging-client-client-credentials"))
                .retrieve()
                .bodyToMono(String[].class)
                .block();
        model.addAttribute("messages", messages);

        return "index";
    }

重点

当使用oauth2登录的时候,redis里面修改为存oauth2认证成功的OAuth2AuthenticationToken
不然会导致确实oauth2登录状态丢失,后面无法退出;无法获取oauth2资源服务的资源


注意点

问题:项目重启后,使用旧有存于redis的自定义token。无法访问Oauth2资源,可以访问本系统资源
原因:我们采用InMemoryOAuth2AuthorizedClientService保存Oauth2的已登录客户端,当我们服务器访问oauth2资源的时候需要通过当前token解析获得的Oauth-registerId来获取该客户端。
解决方案:使用JdbcOAuth2AuthorizedClientService
吐槽:该表的创建sql,用百度搜索是想都不要想,不可能找得到的。然而google却...
image-20211022191835119
image-20211022191914954

CREATE TABLE oauth2_authorized_client (
  client_registration_id varchar(100) NOT NULL,
  principal_name varchar(200) NOT NULL,
  access_token_type varchar(100) NOT NULL,
  access_token_value blob NOT NULL,
  access_token_issued_at timestamp NOT NULL,
  access_token_expires_at timestamp NOT NULL,
  access_token_scopes varchar(1000) DEFAULT NULL,
  refresh_token_value blob DEFAULT NULL,
  refresh_token_issued_at timestamp DEFAULT NULL,
  created_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
  PRIMARY KEY (client_registration_id, principal_name)
);
    /**
     * 自定义OAuth2已授权客户端服务
     */
    @Bean
    public JdbcOAuth2AuthorizedClientService jdbcOAuth2AuthorizedClientService(JdbcTemplate jdbcTemplate,
                                                                               ClientRegistrationRepository clientRegistrationRepository) {
        return new JdbcOAuth2AuthorizedClientService(jdbcTemplate, clientRegistrationRepository);
    }
posted @ 2021-10-22 16:18  临渊不羡渔  阅读(368)  评论(0编辑  收藏  举报