• Spring Security 自定义资源服务器实践


    安装资源服务器

    1、 新建一个Spring Boot项目,命名为 spring-security-resource-server
    2、引入pom.xml依赖

    1. <pre class="prettyprint hljs xml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;"><dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-security</artifactId>
    4. </dependency>
    5. <dependency>
    6. <groupId>org.springframework.boot</groupId>
    7. <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    8. </dependency>
    9. <dependency>
    10. <groupId>org.springframework.boot</groupId>
    11. <artifactId>spring-boot-starter-web</artifactId>
    12. </dependency>

    其中与授权服务器依赖不同的是,资源服务器有spring boot版本,版本号会有spring boot进行管理,不需要显示声明。

    配置资源服务器

    1、配置application.yml 文件

    1. <pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">spring:
    2. security:
    3. oauth2:
    4. resourceserver:
    5. jwt:
    6. issuer-uri: http://localhost:9000

    该配置用于指定授权服务器地址,资源服务器将从该地址获取JWT令牌,并根据JWT中的属性进一步自我配置,发现授权服务器的公钥、验证JWT令牌。

    2、创建配置类

    1. <pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@EnableWebSecurity(debug = true)
    2. public class ResoruceServerConfig {
    3. @Bean
    4. SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    5. http
    6. .authorizeRequests()
    7. .mvcMatchers("/userinfo/**").hasAuthority("SCOPE_userinfo")
    8. .and()
    9. .oauth2ResourceServer()
    10. .jwt();
    11. return http.build();
    12. }
    13. }

    .mvcMatchers("/userinfo/**").hasAuthority("SCOPE_userinfo") 匹配 /userinfo/** 地址,允许访问范围是 SCOPE_userinfo

    oauth2ResourceServer() 定义为资源服务器

    jwt() 使用JWT令牌

    3、 创建一个资源接口

    /userinfo/ 用来获取资源所有者基本信息

    1. <pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Data
    2. public class UserInfoRes {
    3. private String username;
    4. }

    创建Rest接口

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@RestController
    2. public class UserInfoController {
    3. @GetMapping("/userinfo")
    4. public UserInfoRes getUserInfo() {
    5. UserInfoRes userInfoRes = new UserInfoRes();
    6. userInfoRes.setUsername("阿提说说");
    7. return userInfoRes;
    8. }
    9. }

    配置客户端

    目前我们客户端的配置是这样的:

    1. <pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">spring:
    2. security:
    3. oauth2:
    4. client:
    5. registration:
    6. gitee:
    7. client-id: gitee_clientId
    8. client-secret: gitee_secret
    9. authorization-grant-type: authorization_code
    10. redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
    11. client-name: Gitee
    12. github:
    13. client-id: github_clientId
    14. client-secret: github_secret
    15. # 自定义
    16. customize:
    17. client-id: testClientId
    18. client-secret: testClientSecret
    19. authorization-grant-type: authorization_code
    20. redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
    21. client-name: Customize
    22. scope:
    23. - userinfo
    24. provider:
    25. gitee:
    26. authorization-uri: https://gitee.com/oauth/authorize
    27. token-uri: https://gitee.com/oauth/token
    28. user-info-uri: https://gitee.com/api/v5/user
    29. user-name-attribute: name
    30. # 自定义
    31. customize:
    32. authorization-uri: http://localhost:9000/oauth2/authorize
    33. token-uri: http://localhost:9000/oauth2/token
    34. user-info-uri: http://localhost:9000/userinfo
    35. user-name-attribute: username

    这里我们只需要修改 customize 部分的 user-info-uri 和 user-name-attribute
    调整后配置如下,其他部分跟原来是一样的。

    1. <pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">customize:
    2. authorization-uri: http://localhost:9000/oauth2/authorize
    3. token-uri: http://localhost:9000/oauth2/token
    4. user-info-uri: http://localhost:8090/userinfo
    5. user-name-attribute: username

    :exclamation: user-name-attribute的名字,必须在user-info-uri返回的属性名中存在

    整流程体验

    在如上三部分配置完成后,就可以体验了,启动 spring-security-resource-server 、 spring-security-authorization-server 、 spring-security-oauth2-client

    浏览器访问地址: http://127.0.0.1:8080/hello ,在授权完成后,即跳转回并显示结果。

    ResourceServer下能看到带着token的 /userinfo 请求日志。

    1. <pre class="prettyprint hljs markdown" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">************************************************************
    2. Request received for GET '/userinfo':
    3. org.apache.catalina.connector.RequestFacade@3418bfc9
    4. servletPath:/userinfo
    5. pathInfo:null
    6. headers:
    7. accept: application/json
    8. authorization: Bearer eyJraWQiOiI5YjZjZWMzNi05ZDYyLTRkMWMtOWRiNi0wMWM1ODQzMDc1N2UiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoidGVzdENsaWVudElkIiwibmJmIjoxNjYwOTU1ODQyLCJzY29wZSI6WyJ1c2VyaW5mbyJdLCJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6OTAwMCIsImV4cCI6MTY2MDk1NjE0MiwiaWF0IjoxNjYwOTU1ODQyfQ.gVWwwfzB-xNuWWUBpgGokIOy5xwV9Wkd05k3rqpk1h92b-TWENB4ZArEL--zpngSyE8iuml0vG3veCv647FDx_EY56ClM-UxH-3Wq0D2f3b6WTgFO5RpCCwRLCHahBlV5g9plr7hWYY5uX2cQ4MsC4-ltZSR6wga5LSLDB-bIK46ZmJ3DOaQFwTTCpWB4OgOuq1j59i9XkgDUc_I8WUsHB4eEDEbBJeOmdimDn5O1Ux6nDhPgLMLcpnrt3lHLmXDTk8Q7hX7YBynO2VBm6wkTeYP4a2rfinfhW-LtF1o3hm8QAY0hn1QKSEeWU5K5qiIOVeSJ5FqrYJ_VQPadT1qAQ
    9. user-agent: Java/11
    10. host: localhost:8090
    11. connection: keep-alive
    12. Security filter chain: [
    13. DisableEncodeUrlFilter
    14. WebAsyncManagerIntegrationFilter
    15. SecurityContextPersistenceFilter
    16. HeaderWriterFilter
    17. CsrfFilter
    18. LogoutFilter
    19. BearerTokenAuthenticationFilter
    20. RequestCacheAwareFilter
    21. SecurityContextHolderAwareRequestFilter
    22. AnonymousAuthenticationFilter
    23. SessionManagementFilter
    24. ExceptionTranslationFilter
    25. FilterSecurityInterceptor
    26. ]

    到此,我们通过自己搭建的授权服务器和资源服务器,完整体验了OAuth2流程。

    在整个流程中,我们使用的是最严密的授权码模式,它将用户引导到授权服务器进行身份验证,授权服务器将发放的访问令牌传递给客户端,目前主流都是使用该模式, 因此特别重要,要好好体会 。

  • 相关阅读:
    在职阿里3年,一个27岁女软件测试工程师的心声
    扫雷(简化版)(后附完整代码)
    第7章 Elasticsearch面试题
    信息系统项目管理-项目合同管理-十三
    MindSponge分子动力学模拟——软件架构(2023.08)
    利用Java EE相关技术实现一个简单的Web聊天室系统
    低代码平台的核心价值与优势
    贪心 Leetcode 968 监控二叉树
    Linux文件查找、别名、用户组
    Linux之 USB驱动框架-USB鼠标驱动源码分析(5)
  • 原文地址:https://blog.csdn.net/Java_ttcd/article/details/126483364