[关闭]
@File 2019-10-19T07:30:02.000000Z 字数 15404 阅读 125

spring-security oauth2

java


二. 授权服务器的搭建

2.1 依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.security.oauth</groupId>
  7. <artifactId>spring-security-oauth2</artifactId>
  8. <version>2.3.6.RELEASE</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.security.oauth.boot</groupId>
  12. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  13. <version>2.1.9.RELEASE</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>mysql</groupId>
  17. <artifactId>mysql-connector-java</artifactId>
  18. </dependency>
  19. <dependency>
  20. <groupId>com.alibaba</groupId>
  21. <artifactId>druid-spring-boot-starter</artifactId>
  22. <version>1.1.17</version>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-jdbc</artifactId>
  27. </dependency>

2.2 配置

  1. spring:
  2. datasource:
  3. url: jdbc:mysql://mysql:3306/oauth2?useSSL=false&serverTimezone=UTC
  4. username: root
  5. password:
  6. driver-class-name: com.mysql.cj.jdbc.Driver
  7. druid:
  8. initial-size: 20
  9. max-active: 50
  10. min-idle: 15
  11. validation-query: 'select 1'
  12. test-on-borrow: false
  13. test-on-return: false
  14. test-while-idle: true
  15. # psCache, 缓存preparedStatement, 对支持游标的数据库性能有巨大的提升,oracle开启,mysql建议关闭
  16. pool-prepared-statements: false
  17. # psCache开启的时候有效
  18. max-open-prepared-statements: 100
  19. # 一个连接在被驱逐出连接池的时候,在连接池中最小的空闲时间,单位为毫秒
  20. min-evictable-idle-time-millis: 30000
  21. # 距离上次释放空闲连接的时间间隔
  22. time-between-eviction-runs-millis: 30000

2.3 数据库表的创建

  1. create table oauth_client_details (
  2. client_id VARCHAR(256) PRIMARY KEY,
  3. resource_ids VARCHAR(256),
  4. client_secret VARCHAR(256),
  5. scope VARCHAR(256),
  6. authorized_grant_types VARCHAR(256),
  7. web_server_redirect_uri VARCHAR(256),
  8. authorities VARCHAR(256),
  9. access_token_validity INTEGER,
  10. refresh_token_validity INTEGER,
  11. additional_information VARCHAR(4096),
  12. autoapprove VARCHAR(256)
  13. );
  14. create table oauth_client_token (
  15. token_id VARCHAR(256),
  16. token blob,
  17. authentication_id VARCHAR(256) PRIMARY KEY,
  18. user_name VARCHAR(256),
  19. client_id VARCHAR(256)
  20. );
  21. create table oauth_access_token (
  22. token_id VARCHAR(256),
  23. token blob,
  24. authentication_id VARCHAR(256) PRIMARY KEY,
  25. user_name VARCHAR(256),
  26. client_id VARCHAR(256),
  27. authentication blob,
  28. refresh_token VARCHAR(256)
  29. );
  30. create table oauth_refresh_token (
  31. token_id VARCHAR(256),
  32. token blob,
  33. authentication blob
  34. );
  35. create table oauth_code (
  36. code VARCHAR(256), authentication blob
  37. );
  38. create table oauth_approvals (
  39. userId VARCHAR(256),
  40. clientId VARCHAR(256),
  41. scope VARCHAR(256),
  42. status VARCHAR(10),
  43. expiresAt TIMESTAMP,
  44. lastModifiedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  45. );

说明:数据库表是依据spring-security的官网,地址为:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql,但是在创建的时候将所有的字段类型LONGVARBINARY改为BLOB类型。

数据库的说明参考:http://andaily.com/spring-oauth-server/db_table_description.html

2.4 用户登录认证

  1. @Component
  2. public class UserSecurityService implements UserDetailsService {
  3. private static Logger logger = LoggerFactory.getLogger(UserSecurityService.class);
  4. @Override
  5. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  6. logger.info("用户名:" + username);
  7. return new User(username, "$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga",
  8. Arrays.asList(new SimpleGrantedAuthority("ROLE_admin")));
  9. }
  10. }

2.5 web安全配置

  1. @Configuration
  2. public class WebAuthorizationConfig extends WebSecurityConfigurerAdapter {
  3. // 密码的加解密
  4. @Bean
  5. public PasswordEncoder passwordEncoder() {
  6. return new BCryptPasswordEncoder();
  7. }
  8. @Override
  9. protected void configure(HttpSecurity http) throws Exception {
  10. http.formLogin()
  11. .loginPage("/login.html")
  12. .loginProcessingUrl("/authentication/form")
  13. .and()
  14. .authorizeRequests()
  15. .antMatchers("/login.html").permitAll()
  16. .anyRequest()
  17. .authenticated()
  18. .and()
  19. .csrf().disable();
  20. }
  21. }

2.6 授权服务器配置

  1. @Configuration
  2. @EnableAuthorizationServer
  3. public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  4. @Autowired
  5. private LoginAuthencation loginAuthencation;
  6. @Autowired
  7. private PasswordEncoder passwordEncoder;
  8. @Resource
  9. private DataSource dataSource;
  10. // 根据用户的client_id查询用户的授权信息
  11. @Bean
  12. public ClientDetailsService clientDetails() {
  13. return new JdbcClientDetailsService(dataSource);
  14. }
  15. //用于将token信息存放在数据库中
  16. @Bean
  17. public TokenStore tokenStore() {
  18. return new JdbcTokenStore(dataSource);
  19. }
  20. // authentication_code放入到数据中
  21. @Bean
  22. public AuthorizationCodeServices authorizationCodeServices() {
  23. return new JdbcAuthorizationCodeServices(dataSource);
  24. }
  25. @Override
  26. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  27. // 采用数据库的方式查询用户的授权信息
  28. clients.withClientDetails(clientDetails());
  29. /** 供学习使用
  30. clients.inMemory()
  31. // client_id
  32. .withClient("client")
  33. // client_secret
  34. .secret("secret")
  35. // 该client允许的授权类型,不同的类型,则获得token的方式不一样。
  36. .authorizedGrantTypes("authorization_code")
  37. .scopes("all")
  38. //回调uri,在authorization_code与implicit授权方式时,用以接收服务器的返回信息
  39. .redirectUris("http://localhost:9090/login");
  40. */
  41. }
  42. @Override
  43. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  44. // 存数据库
  45. endpoints.tokenStore(tokenStore())
  46. .authorizationCodeServices(authorizationCodeServices())
  47. .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
  48. // 配置tokenServices参数
  49. DefaultTokenServices tokenServices = new DefaultTokenServices();
  50. tokenServices.setTokenStore(endpoints.getTokenStore());
  51. tokenServices.setSupportRefreshToken(false);
  52. tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
  53. tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
  54. // token的过期时间为1天
  55. tokenServices.setAccessTokenValiditySeconds((int)TimeUnit.DAYS.toSeconds(1));
  56. endpoints.tokenServices(tokenServices);
  57. }
  58. @Override
  59. public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
  60. /**
  61. * 作用是使用client_id和client_secret来做登录认证,如果是在浏览器的情况下,会让用户
  62. * 输入用户名和密码
  63. */
  64. oauthServer.allowFormAuthenticationForClients();
  65. oauthServer.checkTokenAccess("isAuthenticated()");
  66. oauthServer.passwordEncoder(passwordEncoder);
  67. }
  68. }

2.7 更改默认授权页面

  1. @Controller
  2. @SessionAttributes("authorizationRequest") // 必须配置
  3. public class AuthController {
  4. /**
  5. * org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint
  6. 默认的授权页面
  7. */
  8. @RequestMapping("/oauth/confirm_access")
  9. public String getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
  10. AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
  11. System.out.println(authorizationRequest.getScope());
  12. return "/oauth.html";
  13. }
  14. }

2.8 获取code

​ 获取授权码的地址:http://127.0.0.1:8080/oauth/authorize?client_id=other_client&response_type=code&redirect_uri=http://localhost:9090/login

​ 在浏览器地址栏的重定向地址上可以看到 code值。

2.9 获取access_token

​ 根据上一步获取到的code值获取acccess_token, 请求的地址为:

http://127.0.0.1:8080/oauth/token?client_id=other_client&client_secret=1&grant_type=authorization_code&code=tuvCj9&redirect_uri=http://localhost:9090/login

​ 其中code的值为上一步请求获取到的code的数据,返回内容如下:

2.10 获取额外的信息

​ Oauth2在获取用户额外信息的时候,内部实现上并没有去做,所以需要我们自己去实现,实现的方式就是去重写其代码,思路是从数据库查询到的信息封装到 ClientDetails中,但是内部却没有开放出来,所以需要去找到是在何处查询数据库,根据源代码的追踪,发现查询数据库的操作是在ApprovalStoreUserApprovalHandler这个类中,所以我们需要手动的去修改其源代码,修改的内容如下:

三. 资源服务器的搭建

​ 资源服务器就是用户想要真正获取资源的服务器,我们必须要通过2.9节中获取到的access_token来获取。

3.1依赖

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.1.9.RELEASE</version>
  5. </parent>
  6. <dependencies>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-web</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.security.oauth</groupId>
  13. <artifactId>spring-security-oauth2</artifactId>
  14. <version>2.3.6.RELEASE</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.springframework.security.oauth.boot</groupId>
  18. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  19. <version>2.1.9.RELEASE</version>
  20. </dependency>
  21. </dependencies>

3.2 配置

  1. security:
  2. oauth2:
  3. resource:
  4. # access_token的验证地址
  5. token-info-uri: http://localhost:8080/oauth/check_token
  6. client:
  7. client-id: resources_client
  8. client-secret: 1

3.3 资源服务账号

​ 我们需要在授权服务器上创建client_id和client_secret,当资源服务器拿到第三方的access_token后需要到授权服务器上验证access_token的来源是否合法。

3.4 资源服务器安全配置

  1. @Configuration
  2. @EnableResourceServer
  3. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  4. @Override
  5. public void configure(HttpSecurity http) throws Exception {
  6. http.authorizeRequests() //
  7. .antMatchers("/user").access("#oauth2.hasAnyScope('all','read')");
  8. }
  9. }

3.5 获取资源

通过调用如下接口去获取资源服务器的资源:

http://localhost:8081/user?access_token=92de29ea-df7d-4d35-b585-c740322f9028

四. JWT(Json Web Token)

4.1 传统跨域登录流程

  1. 用户向服务器发送用户名和密码。
  2. 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中。
  3. 服务器向用户返回session_id,session信息都会写入到用户的Cookie。
  4. 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。
  5. 服务器收到session_id并对比之前保存的数据,确认用户的身份。

​ 这种模式最大的问题是,没有分布式架构,无法支持横向扩展。如果使用一个服务器,该模式完全没有问题。但是,如果它是服务器群集或面向服务的跨域体系结构的话,则需要一个统一的session数据库库来保存会话数据实现共享,这样负载均衡下的每个服务器才可以正确的验证用户身份。

​ 但是在实际中常见的单点登陆的需求:站点A和站点B提供统一公司的相关服务。现在要求用户只需要登录其中一个网站,然后它就会自动登录到另一个网站。怎么做?

​ 一种解决方案是听过持久化session数据,写入数据库或文件持久层等。收到请求后,验证服务从持久层请求数据。该解决方案的优点在于架构清晰,而缺点是架构修改比较费劲,整个服务的验证逻辑层都需要重写,工作量相对较大。而且由于依赖于持久层的数据库或者问题系统,会有单点风险,如果持久层失败,整个认证体系都会挂掉。

4.2 Jwt

​ 针对如上的问题,另外一种解决方案就是JWT(Json Web Token),其原则是在服务器验证之后,将生产的一个Json对象返回给用户,格式如下:

  1. {
  2. "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzEyNDE2NTksInVzZXJfbmFtZSI6ImFhIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9hZG1pbiJdLCJqdGkiOiJlZTczOTI4OC0zNDMwLTQxMjUtODBhOC1lMDU0Njg5OWQ2ODIiLCJjbGllbnRfaWQiOiJteV9jbGllbnQiLCJzY29wZSI6WyJhbGwiXX0.Ji4xYQJuJRrZeCTTMOb1e2GiOESAyiI9NzbWffKzcJ0",
  3. "token_type": "bearer",
  4. "expires_in": 43198,
  5. "scope": "all",
  6. "jti": "ee739288-3430-4125-80a8-e0546899d682"
  7. }

4.2.1 Jwt数据结构

​ 如上代码返回的access_token为一个字符串,之间用 . 分隔为为三段,其中第一段为 header(头),第二段为 payload (负载),第三段为signature(签名),如下图所示:

​ 我们可以在 <https://jwt.io/> 在线解析这个JWT token, 如下图所示

header

字段名 描述
alg 算法
typ 令牌类型

payload

字段名 描述
exp 超时时间
jti JWT ID

signature

​ 签名,为了验证发送过来的access_token是否有效,通过如下算法得到:

4.2.2 用法与问题

​ 客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,因此一般是将它放入HTTP请求的Header Authorization字段中。当跨域时,也可以将JWT被放置于POST请求的数据主体中。

​ 但是JWT也面临着诸多的问题,如下所示:

  1. JWT默认不加密,但可以加密。生成原始令牌后,可以使用改令牌再次对其进行加密。
  2. 当JWT未加密方法是,一些私密数据无法通过JWT传输。
  3. JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。
  4. JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
  5. JWT本身包含认证信息,因此一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证。
  6. 为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。

4.3 jwt授权服务器搭建

依赖:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.1.9.RELEASE</version>
  5. </parent>
  6. <dependencies>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-web</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.security.oauth</groupId>
  13. <artifactId>spring-security-oauth2</artifactId>
  14. <version>2.3.6.RELEASE</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.springframework.security.oauth.boot</groupId>
  18. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  19. <version>2.1.9.RELEASE</version>
  20. </dependency>
  21. </dependencies>

jwt授权服务器

  1. @Configuration
  2. @EnableAuthorizationServer
  3. public class OauthAuthenticationServer extends AuthorizationServerConfigurerAdapter {
  4. @Autowired
  5. private PasswordEncoder passwordEncoder;
  6. @Bean
  7. public TokenStore tokenStore() {
  8. return new JwtTokenStore(jwtAccessTokenConverter());
  9. }
  10. @Bean
  11. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  12. JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  13. jwtAccessTokenConverter.setSigningKey("123"); //设置签名
  14. return jwtAccessTokenConverter;
  15. }
  16. // 基于内存的授权码
  17. @Override
  18. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  19. clients.inMemory() //
  20. .withClient("my_client") //
  21. .secret("$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga") //
  22. .scopes("all") //
  23. .authorizedGrantTypes("authorization_code")
  24. .redirectUris("http://localhost:9090/login");
  25. }
  26. @Override
  27. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  28. endpoints.accessTokenConverter(jwtAccessTokenConverter())
  29. .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
  30. }
  31. @Override
  32. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  33. security.allowFormAuthenticationForClients()
  34. .passwordEncoder(passwordEncoder);
  35. }
  36. }

4.4 jwt资源服务器

  1. @Configuration
  2. @EnableResourceServer
  3. public class ReourceServerConfig extends ResourceServerConfigurerAdapter {
  4. @Bean
  5. public TokenStore jwtTokenStore() {
  6. return new JwtTokenStore(jwtAccessTokenConverter());
  7. }
  8. @Bean
  9. public DefaultTokenServices defaultTokenServices() {
  10. DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
  11. defaultTokenServices.setTokenStore(jwtTokenStore());
  12. return defaultTokenServices;
  13. }
  14. @Bean
  15. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  16. JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  17. jwtAccessTokenConverter.setSigningKey("123");
  18. return jwtAccessTokenConverter;
  19. }
  20. @Override
  21. public void configure(HttpSecurity http) throws Exception {
  22. http.authorizeRequests() //
  23. .anyRequest() //
  24. .authenticated() //
  25. .and() //
  26. .csrf().disable();
  27. }
  28. @Override
  29. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  30. resources.tokenServices(defaultTokenServices());
  31. }
  32. }

五. 单点登录

​ 单点登录(Singal Sign On)是很多企业经常使用的一种登录方式,那么何为单点登录呢?为了解决什么样的问题呢?举个例子,在淘宝公司内部,有天猫、淘宝、阿里云、聚划算等众多的产品线,这些产品线是不同的服务器来支撑运行,但是作为用户的我们却可以使用同一套账户名和密码进行登录他几乎所有的产品,登录服务器只有一个,根据登录服务器返回的特定的信息,可以去访问它所有的产品线。着就是所谓的单点登录。

​ 在具体的实现的时候,我们使用JWT的方式来实现单点登录。他的处理流程如下:

5.1 认证服务器

依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.security.oauth</groupId>
  8. <artifactId>spring-security-oauth2</artifactId>
  9. <version>2.3.6.RELEASE</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.security.oauth.boot</groupId>
  13. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  14. <version>2.1.9.RELEASE</version>
  15. </dependency>
  16. </dependencies>

授权服务

  1. @Configuration
  2. @EnableAuthorizationServer
  3. public class SsoAuthorizationConfigServer extends AuthorizationServerConfigurerAdapter {
  4. @Bean
  5. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  6. JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  7. jwtAccessTokenConverter.setSigningKey("abcxyz");
  8. return jwtAccessTokenConverter;
  9. }
  10. @Override
  11. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  12. clients.inMemory() //
  13. .withClient("client-a") //
  14. .secret("$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga") //
  15. .authorizedGrantTypes("authorization_code", "refresh_token")
  16. .scopes("all")
  17. .redirectUris("http://localhost:8081/clientA/login")
  18. .autoApprove(true)
  19. .and()
  20. .withClient("client-b") //
  21. .secret("$2a$10$TWf8wOKvyAeuJiL/gj8AfeWOrW9vr6g4Q6kJ.PZ1bt53ISRXTTcga") //
  22. .authorizedGrantTypes("authorization_code")
  23. .scopes("all")
  24. .redirectUris("http://localhost:8082/clientB/login")
  25. .autoApprove(true);
  26. }
  27. @Override
  28. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  29. endpoints//.tokenStore(jwtTokenStore())
  30. .accessTokenConverter(jwtAccessTokenConverter());
  31. }
  32. }

5.2 子系统

依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.security.oauth</groupId>
  8. <artifactId>spring-security-oauth2</artifactId>
  9. <version>2.3.6.RELEASE</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-security</artifactId>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework.security.oauth.boot</groupId>
  17. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  18. <version>2.1.9.RELEASE</version>
  19. </dependency>
  20. </dependencies>

配置

  1. server:
  2. port: 8081
  3. servlet:
  4. context-path: /clientA
  5. security:
  6. oauth2:
  7. client:
  8. client-id: client-a
  9. client-secret: 1
  10. access-token-uri: http://localhost:7070/auth/oauth/token
  11. user-authorization-uri: http://localhost:7070/auth/oauth/authorize
  12. resource:
  13. jwt:
  14. key-value: abcxyz

启动类配置

  1. @SpringBootApplication
  2. @EnableOAuth2Sso
  3. public class SsoClientApplicationA {
  4. public static void main( String[] args ) {
  5. SpringApplication.run(SsoClientApplicationA.class, args);
  6. }
  7. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注