当前位置:   article > 正文

SpringCloud OAuth2搭建(学习记录)_spring-security-oauth2-autoconfigure

spring-security-oauth2-autoconfigure

一,认证服务器端:

Maven依赖

  1. <!--导入spring cloud oauth2依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-oauth2</artifactId>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.springframework.security.oauth.boot</groupId>
  8. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.security.oauth.boot</groupId>
  14. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  15. <version>2.1.11.RELEASE</version>
  16. </dependency>
  17. <!--引入security对oauth2的支持-->
  18. <dependency>
  19. <groupId>org.springframework.security.oauth</groupId>
  20. <artifactId>spring-security-oauth2</artifactId>
  21. <version>2.3.4.RELEASE</version>
  22. </dependency>

Yaml配置

  1. server:
  2. port: 9999
  3. Spring:
  4. application:
  5. name: cloud-oauth-server
  6. datasource:
  7. driver-class-name: com.mysql.jdbc.Driver
  8. url: jdbc:mysql://XXX:XXX/private_chat?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=GMT%2B8&useSSL=false
  9. username: XXX
  10. password: XXX
  11. druid:
  12. initialSize: 10
  13. minIdle: 10
  14. maxActive: 30
  15. maxWait: 50000
  16. eureka:
  17. client:
  18. serviceUrl: # eureka server的路径
  19. defaultZone: http://CloudeurekaserverB:8761/eureka/,http://CloudeurekaserverB:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表
  20. instance:
  21. #使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
  22. prefer-ip-address: true
  23. #自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
  24. instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@

OAuth2配置类(基础配置、JWT、JPA框架下的数据库连接获取)

  1. /**
  2. * 当前类为Oauth2 server的配置类(需要继承特定的父类 AuthorizationServerConfigurerAdapter)
  3. */
  4. @Configuration
  5. @EnableAuthorizationServer // 开启认证服务器功能
  6. public class OauthServerConfiger extends AuthorizationServerConfigurerAdapter {
  7. @Autowired
  8. private AuthenticationManager authenticationManager;
  9. @Autowired
  10. private LagouAccessTokenConvertor lagouAccessTokenConvertor;
  11. private String sign_key = "lagou123"; // jwt签名密钥
  12. /**
  13. * 认证服务器最终是以api接口的方式对外提供服务(校验合法性并生成令牌、校验令牌等)
  14. * 那么,以api接口方式对外的话,就涉及到接口的访问权限,我们需要在这里进行必要的配置
  15. * @param security
  16. * @throws Exception
  17. */
  18. @Override
  19. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  20. super.configure(security);
  21. // 相当于打开endpoints 访问接口的开关,这样的话后期我们能够访问该接口
  22. security
  23. // 允许客户端表单认证
  24. .allowFormAuthenticationForClients()
  25. // 开启端口/oauth/token_key的访问权限(允许)
  26. .tokenKeyAccess("permitAll()")
  27. // 开启端口/oauth/check_token的访问权限(允许)
  28. .checkTokenAccess("permitAll()");
  29. }
  30. /**
  31. * 客户端详情配置,
  32. * 比如client_id,secret
  33. * 当前这个服务就如同QQ平台,拉勾网作为客户端需要qq平台进行登录授权认证等,提前需要到QQ平台注册,QQ平台会给拉勾网
  34. * 颁发client_id等必要参数,表明客户端是谁
  35. * @param clients
  36. * @throws Exception
  37. */
  38. @Override
  39. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  40. super.configure(clients);
  41. // 从内存中加载客户端详情
  42. /*clients.inMemory()// 客户端信息存储在什么地方,可以在内存中,可以在数据库里
  43. .withClient("client_lagou") // 添加一个client配置,指定其client_id
  44. .secret("abcxyz") // 指定客户端的密码/安全码
  45. .resourceIds("autodeliver") // 指定客户端所能访问资源id清单,此处的资源id是需要在具体的资源服务器上也配置一样
  46. // 认证类型/令牌颁发模式,可以配置多个在这里,但是不一定都用,具体使用哪种方式颁发token,需要客户端调用的时候传递参数指定
  47. .authorizedGrantTypes("password","refresh_token")
  48. // 客户端的权限范围,此处配置为all全部即可
  49. .scopes("all");*/
  50. // 从数据库中加载客户端详情
  51. clients.withClientDetails(createJdbcClientDetailsService());
  52. }
  53. @Autowired
  54. private DataSource dataSource;
  55. @Bean
  56. public JdbcClientDetailsService createJdbcClientDetailsService() {
  57. JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
  58. return jdbcClientDetailsService;
  59. }
  60. /**
  61. * 认证服务器是玩转token的,那么这里配置token令牌管理相关(token此时就是一个字符串,当下的token需要在服务器端存储,
  62. * 那么存储在哪里呢?都是在这里配置)
  63. * @param endpoints
  64. * @throws Exception
  65. */
  66. @Override
  67. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  68. super.configure(endpoints);
  69. endpoints
  70. .tokenStore(tokenStore()) // 指定token的存储方法
  71. .tokenServices(authorizationServerTokenServices()) // token服务的一个描述,可以认为是token生成细节的描述,比如有效时间多少等
  72. .authenticationManager(authenticationManager) // 指定认证管理器,随后注入一个到当前类使用即可
  73. .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
  74. }
  75. /*
  76. 该方法用于创建tokenStore对象(令牌存储对象)
  77. token以什么形式存储
  78. */
  79. public TokenStore tokenStore(){
  80. //return new InMemoryTokenStore();
  81. // 使用jwt令牌
  82. return new JwtTokenStore(jwtAccessTokenConverter());
  83. }
  84. /**
  85. * 返回jwt令牌转换器(帮助我们生成jwt令牌的)
  86. * 在这里,我们可以把签名密钥传递进去给转换器对象
  87. * @return
  88. */
  89. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  90. JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  91. jwtAccessTokenConverter.setSigningKey(sign_key); // 签名密钥
  92. jwtAccessTokenConverter.setVerifier(new MacSigner(sign_key)); // 验证时使用的密钥,和签名密钥保持一致
  93. jwtAccessTokenConverter.setAccessTokenConverter(lagouAccessTokenConvertor);
  94. return jwtAccessTokenConverter;
  95. }
  96. /**
  97. * 该方法用户获取一个token服务对象(该对象描述了token有效期等信息)
  98. */
  99. public AuthorizationServerTokenServices authorizationServerTokenServices() {
  100. // 使用默认实现
  101. DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
  102. defaultTokenServices.setSupportRefreshToken(true); // 是否开启令牌刷新
  103. defaultTokenServices.setTokenStore(tokenStore());
  104. // 针对jwt令牌的添加
  105. defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
  106. // 设置令牌有效时间(一般设置为2个小时)
  107. defaultTokenServices.setAccessTokenValiditySeconds(20); // access_token就是我们请求资源需要携带的令牌
  108. // 设置刷新令牌的有效时间
  109. defaultTokenServices.setRefreshTokenValiditySeconds(259200); // 3天
  110. return defaultTokenServices;
  111. }
  112. }

验证令牌数据库存储情况下的用户名与密码验证类(数据库操作省略)

  1. /**
  2. * 该配置类,主要处理用户名和密码的校验等事宜
  3. */
  4. @Configuration
  5. public class SecurityConfiger extends WebSecurityConfigurerAdapter {
  6. @Autowired
  7. private PasswordEncoder passwordEncoder;
  8. @Autowired
  9. private JdbcUserDetailsService jdbcUserDetailsService;
  10. /**
  11. * 注册一个认证管理器对象到容器
  12. */
  13. @Bean
  14. @Override
  15. public AuthenticationManager authenticationManagerBean() throws Exception {
  16. return super.authenticationManagerBean();
  17. }
  18. /**
  19. * 密码编码对象(密码不进行加密处理)
  20. * @return
  21. */
  22. @Bean
  23. public PasswordEncoder passwordEncoder() {
  24. return NoOpPasswordEncoder.getInstance();
  25. }
  26. /**
  27. * 处理用户名和密码验证事宜
  28. * 1)客户端传递username和password参数到认证服务器
  29. * 2)一般来说,username和password会存储在数据库中的用户表中
  30. * 3)根据用户表中数据,验证当前传递过来的用户信息的合法性
  31. */
  32. @Override
  33. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  34. // 在这个方法中就可以去关联数据库了,当前我们先把用户信息配置在内存中
  35. // 实例化一个用户对象(相当于数据表中的一条用户记录)
  36. /*UserDetails user = new User("admin","123456",new ArrayList<>());
  37. auth.inMemoryAuthentication()
  38. .withUser(user).passwordEncoder(passwordEncoder);*/
  39. auth.userDetailsService(jdbcUserDetailsService).passwordEncoder(passwordEncoder);
  40. }
  41. }

 从认证服务端获取令牌,令牌内容注入配置

  1. @Component
  2. public class AccessTokenConvertor extends DefaultAccessTokenConverter {
  3. @Override
  4. public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
  5. // 获取到request对象
  6. HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.getRequestAttributes())).getRequest();
  7. // 获取客户端ip(注意:如果是经过代理之后到达当前服务的话,那么这种方式获取的并不是真实的浏览器客户端ip)
  8. String remoteAddr = request.getRemoteAddr();
  9. Map<String, String> stringMap = (Map<String, String>) super.convertAccessToken(token, authentication);
  10. stringMap.put("clientIp",remoteAddr);
  11. return stringMap;
  12. }
  13. }

二,网关配置

  1. spring:
  2. application:
  3. name: cloud-gateway
  4. cloud:
  5. gateway:
  6. routes: # 路由可以有多个
  7. - id: service-oauth-router # 我们自定义的路由 ID,保持唯一
  8. uri: lb://cloud-oauth-server # gateway网关从服务注册中心获取实例信息然后负载后路由
  9. predicates: # 断言:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默 认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
  10. - Path=/oauth/**

三,请求认证服务端

oauth2基本使用情况下,服务器端对认证服务请求判断自己的获取的令牌是否正确,如果服务端过多会导致认证服务器端压力过大。故通过JWT或者数据库端的令牌持久化来进行自我认证,JWT通过统一签名秘钥自身通过算法来解析是否正确。

Maven依赖

  1. <!--导入spring cloud oauth2依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-oauth2</artifactId>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.springframework.security.oauth.boot</groupId>
  8. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.security.oauth.boot</groupId>
  14. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  15. <version>2.1.11.RELEASE</version>
  16. </dependency>
  17. <!--引入security对oauth2的支持-->
  18. <dependency>
  19. <groupId>org.springframework.security.oauth</groupId>
  20. <artifactId>spring-security-oauth2</artifactId>
  21. <version>2.3.4.RELEASE</version>
  22. </dependency>

yaml配置

  1. oauth2:
  2. server:
  3. check-token-url: http://localhost:9999/oauth/check_token

服务令牌认证配置类

  1. @Configuration
  2. @EnableResourceServer // 开启资源服务器功能
  3. @EnableWebSecurity // 开启web访问安全
  4. public class ResourceServerConfiger extends ResourceServerConfigurerAdapter {
  5. private String sign_key = "Test123"; // jwt签名密钥
  6. @Autowired
  7. private LagouAccessTokenConvertor lagouAccessTokenConvertor;
  8. /**
  9. * 该方法用于定义资源服务器向远程认证服务器发起请求,进行token校验等事宜
  10. * @param resources
  11. * @throws Exception
  12. */
  13. @Override
  14. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  15. /*// 设置当前资源服务的资源id
  16. resources.resourceId("autodeliver");
  17. // 定义token服务对象(token校验就应该靠token服务对象)
  18. RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
  19. // 校验端点/接口设置
  20. remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:9999/oauth/check_token");
  21. // 携带客户端id和客户端安全码
  22. remoteTokenServices.setClientId("client_lagou");
  23. remoteTokenServices.setClientSecret("abcxyz");
  24. // 别忘了这一步
  25. resources.tokenServices(remoteTokenServices);*/
  26. // jwt令牌改造
  27. resources.resourceId("autodeliver").tokenStore(tokenStore()).stateless(true);// 无状态设置
  28. }
  29. /**
  30. * 场景:一个服务中可能有很多资源(API接口)
  31. * 某一些API接口,需要先认证,才能访问
  32. * 某一些API接口,压根就不需要认证,本来就是对外开放的接口
  33. * 我们就需要对不同特点的接口区分对待(在当前configure方法中完成),设置是否需要经过认证
  34. *
  35. * @param http
  36. * @throws Exception
  37. */
  38. @Override
  39. public void configure(HttpSecurity http) throws Exception {
  40. http // 设置session的创建策略(根据需要创建即可)
  41. .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
  42. .and()
  43. .authorizeRequests()
  44. .antMatchers("/autodeliver/**").authenticated() // autodeliver为前缀的请求需要认证
  45. .antMatchers("/demo/**").authenticated() // demo为前缀的请求需要认证
  46. .anyRequest().permitAll(); // 其他请求不认证
  47. }
  48. /*
  49. 该方法用于创建tokenStore对象(令牌存储对象)
  50. token以什么形式存储
  51. */
  52. public TokenStore tokenStore(){
  53. //return new InMemoryTokenStore();
  54. // 使用jwt令牌
  55. return new JwtTokenStore(jwtAccessTokenConverter());
  56. }
  57. /**
  58. * 返回jwt令牌转换器(帮助我们生成jwt令牌的)
  59. * 在这里,我们可以把签名密钥传递进去给转换器对象
  60. * @return
  61. */
  62. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  63. JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  64. jwtAccessTokenConverter.setSigningKey(sign_key); // 签名密钥
  65. jwtAccessTokenConverter.setVerifier(new MacSigner(sign_key)); // 验证时使用的密钥,和签名密钥保持一致
  66. jwtAccessTokenConverter.setAccessTokenConverter(lagouAccessTokenConvertor);
  67. return jwtAccessTokenConverter;
  68. }
  69. }

令牌使用

  1. @Component
  2. public class AccessTokenConvertor extends DefaultAccessTokenConverter {
  3. @Override
  4. public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
  5. OAuth2Authentication oAuth2Authentication = super.extractAuthentication(map);
  6. oAuth2Authentication.setDetails(map); // 将map放入认证对象中,认证对象在controller中可以拿到
  7. return oAuth2Authentication;
  8. }
  9. }

控制层代码(两种模式下):

  1. @GetMapping("/test")
  2. public String findResumeOpenState() {
  3. Object details = SecurityContextHolder.getContext().getAuthentication().getDetails();
  4. return "demo/test!";
  5. }
  6. @GetMapping("/test")
  7. public String findResumeOpenState() {
  8. return "others/test!";
  9. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/83414
推荐阅读
相关标签
  

闽ICP备14008679号