当前位置:   article > 正文

Spring cloud OAuth2_spring-cloud-starter-oauth2

spring-cloud-starter-oauth2

1、OAuth2.0简介

OAuth(开发授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。

OAuth2.0是OAuth的延续,但他并不兼容OAuth1.0,即它完全废除OAuth1.0。很多大公司如Google,Yahoo,Microsoft等都提供了OAuth认证服 务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。

微信小程序授权登录同样也是提供OAuth认证服务

2、业务场景

第三方认证

当需要访问第三方系统的资源时需要首先通过第三方系统的认证(例如:微信认证),由第三方系统对用户认证通过,并授权资源的访问权限。

你恰好之前在我们的B网站上注册过账号,那么现在就可以使用B网站上的账号登录在CSDN上。那么我们在B网站上做这样的一个功能就是使用OAuth2做的。

OAuth2.0包含一下几种角色

1,客户端:本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源。

2,资源拥有者:通常为用户,也可以是应用程序,即该资源的拥有者。

3,授权服务器(认证服务器):用于服务提供商对资源拥有者的身份认证,对访问资源进行授权,认证成功后会给客户端发放令牌(access_token),作为客户端访问资源服务器的凭据。

4,资源服务器:存储资源的服务器

5,客户端标识:client_id

6,客户端密钥:client_secret

为什么要有client_id和client_secret呢?

因为服务提供商不能允许随便一个客户端就接入到它的授权服务器,服务提供商会 给准入的接入方一个身份,用于接入时的凭据。

3,环境搭建

  1. 项目工程

shop-oauth-service 认证服务(颁发Token)

shop-gateway-service 网关(认证用户的请求 也即认证Token)

shop-service 服务(资源服务)

  1. 项目依赖pom.xml文件

1.父模块pom.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <parent>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-parent</artifactId>
  9. <version>2.1.8.RELEASE</version>
  10. </parent>
  11. <groupId>com.lpz</groupId>
  12. <artifactId>shop-parent</artifactId>
  13. <packaging>pom</packaging>
  14. <version>1.0-SNAPSHOT</version>
  15. <modules>
  16. <module>shop-server</module>
  17. <module>shop-api</module>
  18. <module>shop-gateway-server</module>
  19. <module>shop-oauth-server</module>
  20. </modules>
  21. <properties>
  22. <maven.compiler.source>8</maven.compiler.source>
  23. <maven.compiler.target>8</maven.compiler.target>
  24. <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
  25. </properties>
  26. <dependencyManagement>
  27. <dependencies>
  28. <dependency>
  29. <groupId>org.springframework.cloud</groupId>
  30. <artifactId>spring-cloud-dependencies</artifactId>
  31. <version>${spring-cloud.version}</version>
  32. <type>pom</type>
  33. <scope>import</scope>
  34. </dependency>
  35. <dependency>
  36. <groupId>com.alibaba.cloud</groupId>
  37. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  38. <version>2.1.0.RELEASE</version>
  39. <type>pom</type>
  40. <scope>import</scope>
  41. </dependency>
  42. </dependencies>
  43. </dependencyManagement>
  44. </project>

2.网关模块pom.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>shop-parent</artifactId>
  7. <groupId>com.lpz</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>shop-gateway-server</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.cloud</groupId>
  19. <artifactId>spring-cloud-starter-gateway</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>com.alibaba.cloud</groupId>
  23. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  24. </dependency>
  25. </dependencies>
  26. </project>

3.shop-server模块pom.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>shop-parent</artifactId>
  7. <groupId>com.lpz</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>shop-server</artifactId>
  12. <packaging>pom</packaging>
  13. <modules>
  14. <module>shop-user-server</module>
  15. <module>shop-goods-server</module>
  16. </modules>
  17. <properties>
  18. <maven.compiler.source>8</maven.compiler.source>
  19. <maven.compiler.target>8</maven.compiler.target>
  20. </properties>
  21. <dependencies>
  22. <dependency>
  23. <groupId>mysql</groupId>
  24. <artifactId>mysql-connector-java</artifactId>
  25. </dependency>
  26. <!-- 服务注册/发现-->
  27. <dependency>
  28. <groupId>com.alibaba.cloud</groupId>
  29. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  30. </dependency>
  31. <dependency>
  32. <groupId>com.baomidou</groupId>
  33. <artifactId>mybatis-plus-boot-starter</artifactId>
  34. <version>3.3.1.tmp</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-test</artifactId>
  39. <scope>test</scope>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.springframework.boot</groupId>
  43. <artifactId>spring-boot-starter-web</artifactId>
  44. </dependency>
  45. <dependency>
  46. <groupId>org.springframework.cloud</groupId>
  47. <artifactId>spring-cloud-starter-oauth2</artifactId>
  48. </dependency>
  49. </dependencies>
  50. </project>

4.shop-oauth-server模块pom.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>shop-parent</artifactId>
  7. <groupId>com.lpz</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>shop-oauth-server</artifactId>
  12. <dependencies>
  13. <!-- 服务注册/发现-->
  14. <dependency>
  15. <groupId>com.alibaba.cloud</groupId>
  16. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-web</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId>mysql</groupId>
  24. <artifactId>mysql-connector-java</artifactId>
  25. <scope>runtime</scope>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.mybatis.spring.boot</groupId>
  29. <artifactId>mybatis-spring-boot-starter</artifactId>
  30. <version>1.1.1</version>
  31. </dependency>
  32. <dependency>
  33. <groupId>io.jsonwebtoken</groupId>
  34. <artifactId>jjwt</artifactId>
  35. <version>0.9.0</version>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.springframework.security</groupId>
  39. <artifactId>spring-security-data</artifactId>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.springframework.cloud</groupId>
  43. <artifactId>spring-cloud-starter-oauth2</artifactId>
  44. <exclusions>
  45. <exclusion>
  46. <groupId>org.springframework.security.oauth.boot</groupId>
  47. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  48. </exclusion>
  49. </exclusions>
  50. </dependency>
  51. <dependency>
  52. <groupId>org.springframework.security.oauth.boot</groupId>
  53. <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  54. <version>2.1.3.RELEASE</version>
  55. </dependency>
  56. <dependency>
  57. <groupId>org.springframework.cloud</groupId>
  58. <artifactId>spring-cloud-starter-security</artifactId>
  59. </dependency>
  60. <dependency>
  61. <groupId>org.springframework.boot</groupId>
  62. <artifactId>spring-boot-starter-actuator</artifactId>
  63. </dependency>
  64. <dependency>
  65. <groupId>com.lpz</groupId>
  66. <artifactId>shop-user-api</artifactId>
  67. <version>1.0-SNAPSHOT</version>
  68. </dependency>
  69. </dependencies>
  70. </project>

shop-oauth-server yml配置文件

  1. server:
  2. port: 1100
  3. spring:
  4. application:
  5. name: user-auth
  6. datasource:
  7. driver-class-name: com.mysql.jdbc.Driver
  8. url: jdbc:mysql://127.0.0.1:3306/shop_oauth?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
  9. username: root
  10. password: abc123
  11. main:
  12. allow-bean-definition-overriding: true
  13. cloud:
  14. nacos:
  15. discovery:
  16. server-addr: 192.168.56.1:8848
  17. auth:
  18. ttl: 3600 #token存储到redis的过期时间
  19. clientId: accp
  20. clientSecret: accp
  21. cookieDomain: localhost
  22. cookieMaxAge: -1
  23. encrypt:
  24. key-store:
  25. location: classpath:/wfshop.jks
  26. secret: wfshop
  27. alias: wfshop
  28. password: wfshop

AuthorizationServerConfig配置类

  1. package com.lpz.oauth.config;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.cloud.bootstrap.encrypt.KeyProperties;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.security.authentication.AuthenticationManager;
  7. import org.springframework.security.core.userdetails.UserDetailsService;
  8. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  9. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  10. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  11. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  12. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  13. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  14. import org.springframework.security.oauth2.provider.ClientDetailsService;
  15. import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
  16. import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
  17. import org.springframework.security.oauth2.provider.token.TokenStore;
  18. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  19. import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
  20. import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
  21. import javax.annotation.Resource;
  22. import javax.sql.DataSource;
  23. import java.security.KeyPair;
  24. @Configuration
  25. @EnableAuthorizationServer
  26. class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  27. //数据源,用于从数据库获取数据进行认证操作,测试可以从内存中获取
  28. @Autowired
  29. private DataSource dataSource;
  30. //jwt令牌转换器
  31. @Autowired
  32. private JwtAccessTokenConverter jwtAccessTokenConverter;
  33. //SpringSecurity 用户自定义授权认证类
  34. @Autowired
  35. UserDetailsService userDetailsService;
  36. //授权认证管理器
  37. @Autowired
  38. AuthenticationManager authenticationManager;
  39. //令牌持久化存储接口
  40. @Autowired
  41. TokenStore tokenStore;
  42. @Autowired
  43. private CustomUserAuthenticationConverter customUserAuthenticationConverter;
  44. /***
  45. * 客户端信息配置
  46. * @param clients
  47. * @throws Exception
  48. */
  49. @Override
  50. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  51. clients.jdbc(dataSource).clients(clientDetails());
  52. // clients.inMemory()
  53. // .withClient("changgou") //客户端id
  54. // .secret("changgou") //秘钥
  55. // .redirectUris("http://localhost") //重定向地址
  56. // .accessTokenValiditySeconds(3600) //访问令牌有效期
  57. // .refreshTokenValiditySeconds(3600) //刷新令牌有效期
  58. // .authorizedGrantTypes(
  59. // "authorization_code", //根据授权码生成令牌
  60. // "client_credentials", //客户端认证
  61. // "refresh_token", //刷新令牌
  62. // "password") //密码方式认证
  63. // .scopes("app"); //客户端范围,名称自定义,必填
  64. }
  65. /***
  66. * 授权服务器端点配置
  67. * @param endpoints
  68. * @throws Exception
  69. */
  70. @Override
  71. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  72. endpoints.accessTokenConverter(jwtAccessTokenConverter)
  73. .authenticationManager(authenticationManager)//认证管理器
  74. .tokenStore(tokenStore) //令牌存储
  75. .userDetailsService(userDetailsService); //用户信息service
  76. }
  77. /***
  78. * 授权服务器的安全配置
  79. * @param oauthServer
  80. * @throws Exception
  81. */
  82. @Override
  83. public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
  84. oauthServer.allowFormAuthenticationForClients()
  85. .passwordEncoder(new BCryptPasswordEncoder())
  86. .tokenKeyAccess("permitAll()")
  87. .checkTokenAccess("isAuthenticated()");
  88. }
  89. //读取密钥的配置
  90. @Bean("keyProp")
  91. public KeyProperties keyProperties(){
  92. return new KeyProperties();
  93. }
  94. @Resource(name = "keyProp")
  95. private KeyProperties keyProperties;
  96. //客户端配置
  97. @Bean
  98. public ClientDetailsService clientDetails() {
  99. return new JdbcClientDetailsService(dataSource);
  100. }
  101. @Bean
  102. @Autowired
  103. public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
  104. return new JwtTokenStore(jwtAccessTokenConverter);
  105. }
  106. /****
  107. * JWT令牌转换器
  108. * @param customUserAuthenticationConverter
  109. * @return
  110. */
  111. @Bean
  112. public JwtAccessTokenConverter jwtAccessTokenConverter(CustomUserAuthenticationConverter customUserAuthenticationConverter) {
  113. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  114. KeyPair keyPair = new KeyStoreKeyFactory(
  115. keyProperties.getKeyStore().getLocation(), //证书路径 changgou.jks
  116. keyProperties.getKeyStore().getSecret().toCharArray()) //证书秘钥 changgouapp
  117. .getKeyPair(
  118. keyProperties.getKeyStore().getAlias(), //证书别名 changgou
  119. keyProperties.getKeyStore().getPassword().toCharArray()); //证书密码 changgou
  120. converter.setKeyPair(keyPair);
  121. //配置自定义的CustomUserAuthenticationConverter
  122. DefaultAccessTokenConverter accessTokenConverter = (DefaultAccessTokenConverter) converter.getAccessTokenConverter();
  123. accessTokenConverter.setUserTokenConverter(customUserAuthenticationConverter);
  124. return converter;
  125. }
  126. }

CustomUserAuthenticationConverter类

  1. package com.lpz.oauth.config;
  2. import com.lpz.oauth.util.UserJwt;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.security.core.Authentication;
  5. import org.springframework.security.core.authority.AuthorityUtils;
  6. import org.springframework.security.core.userdetails.UserDetails;
  7. import org.springframework.security.core.userdetails.UserDetailsService;
  8. import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
  9. import org.springframework.stereotype.Component;
  10. import java.util.LinkedHashMap;
  11. import java.util.Map;
  12. @Component
  13. public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
  14. @Autowired
  15. UserDetailsService userDetailsService;
  16. @Override
  17. public Map<String, ?> convertUserAuthentication(Authentication authentication) {
  18. LinkedHashMap response = new LinkedHashMap();
  19. String name = authentication.getName();
  20. response.put("username", name);
  21. Object principal = authentication.getPrincipal();
  22. UserJwt userJwt = null;
  23. if(principal instanceof UserJwt){
  24. userJwt = (UserJwt) principal;
  25. }else{
  26. //refresh_token默认不去调用userdetailService获取用户信息,这里我们手动去调用,得到 UserJwt
  27. UserDetails userDetails = userDetailsService.loadUserByUsername(name);
  28. userJwt = (UserJwt) userDetails;
  29. }
  30. response.put("name", userJwt.getName());
  31. response.put("id", userJwt.getId());
  32. //公司 response.put("compy", "songsi");
  33. if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
  34. response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
  35. }
  36. return response;
  37. }
  38. }

UserDetailsServiceImpl实现类

  1. package com.lpz.oauth.config;
  2. import com.lpz.dto.TbUserDto;
  3. import com.lpz.feign.UserFeignService;
  4. import com.lpz.oauth.util.UserJwt;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.security.core.Authentication;
  7. import org.springframework.security.core.authority.AuthorityUtils;
  8. import org.springframework.security.core.context.SecurityContextHolder;
  9. import org.springframework.security.core.userdetails.User;
  10. import org.springframework.security.core.userdetails.UserDetails;
  11. import org.springframework.security.core.userdetails.UserDetailsService;
  12. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  13. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  14. import org.springframework.security.oauth2.provider.ClientDetails;
  15. import org.springframework.security.oauth2.provider.ClientDetailsService;
  16. import org.springframework.stereotype.Service;
  17. import org.springframework.util.StringUtils;
  18. /*****
  19. * 自定义授权认证类
  20. */
  21. @Service
  22. public class UserDetailsServiceImpl implements UserDetailsService {
  23. @Autowired
  24. ClientDetailsService clientDetailsService;
  25. @Autowired
  26. UserFeignService userFeignService;
  27. /****
  28. * 自定义授权认证
  29. * @param username
  30. * @return
  31. * @throws UsernameNotFoundException
  32. */
  33. @Override
  34. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  35. //取出身份,如果身份为空说明没有认证
  36. Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  37. //没有认证统一采用httpbasic认证,httpbasic中存储了client_id和client_secret,开始认证client_id和client_secret
  38. if (authentication == null) {
  39. ClientDetails clientDetails = clientDetailsService.loadClientByClientId(username);
  40. if (clientDetails != null) {
  41. //秘钥
  42. String clientSecret = clientDetails.getClientSecret();
  43. //静态方式
  44. // return new User(username,new BCryptPasswordEncoder().encode(clientSecret), AuthorityUtils.commaSeparatedStringToAuthorityList(""));
  45. //数据库查找方式
  46. return new User(username, clientSecret, AuthorityUtils.commaSeparatedStringToAuthorityList(""));
  47. }
  48. }
  49. if (StringUtils.isEmpty(username)) {
  50. return null;
  51. }
  52. //根据用户名查询用户信息
  53. TbUserDto info = userFeignService.info(username);
  54. String pwd = info.getPassword();
  55. //创建User对象
  56. String permissions = "goods_list,seckill_list";
  57. UserJwt userDetails = new UserJwt(username, pwd, AuthorityUtils.commaSeparatedStringToAuthorityList(permissions));
  58. //userDetails.setComy(songsi);
  59. return userDetails;
  60. }
  61. }

WebSecurityConfig配置类

  1. package com.lpz.oauth.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.core.annotation.Order;
  5. import org.springframework.security.authentication.AuthenticationManager;
  6. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  7. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  9. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  10. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  11. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  12. import org.springframework.security.crypto.password.PasswordEncoder;
  13. @Configuration
  14. @EnableWebSecurity
  15. @Order(-1)
  16. class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  17. /***
  18. * 忽略安全拦截的URL
  19. * @param web
  20. * @throws Exception
  21. */
  22. @Override
  23. public void configure(WebSecurity web) throws Exception {
  24. web.ignoring().antMatchers(
  25. "/oauth/login",
  26. "/user/logout");
  27. }
  28. /***
  29. * 创建授权管理认证对象
  30. * @return
  31. * @throws Exception
  32. */
  33. @Bean
  34. @Override
  35. public AuthenticationManager authenticationManagerBean() throws Exception {
  36. AuthenticationManager manager = super.authenticationManagerBean();
  37. return manager;
  38. }
  39. @Override
  40. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  41. super.configure(auth);
  42. }
  43. /***
  44. * 采用BCryptPasswordEncoder对密码进行编码
  45. * @return
  46. */
  47. @Bean
  48. public PasswordEncoder passwordEncoder() {
  49. return new BCryptPasswordEncoder();
  50. }
  51. /****
  52. *
  53. * @param http
  54. * @throws Exception
  55. */
  56. @Override
  57. public void configure(HttpSecurity http) throws Exception {
  58. http.csrf().disable()
  59. .httpBasic() //启用Http基本身份验证
  60. .and()
  61. .formLogin() //启用表单身份验证
  62. .and()
  63. .authorizeRequests() //限制基于Request请求访问
  64. .anyRequest()
  65. .authenticated(); //其他请求都需要经过验证
  66. }
  67. }

AuthToken工具类

  1. package com.lpz.oauth.util;
  2. import java.io.Serializable;
  3. public class AuthToken implements Serializable{
  4. //令牌信息
  5. String accessToken;
  6. //刷新token(refresh_token)
  7. String refreshToken;
  8. //jwt短令牌
  9. String jti;
  10. public String getAccessToken() {
  11. return accessToken;
  12. }
  13. public void setAccessToken(String accessToken) {
  14. this.accessToken = accessToken;
  15. }
  16. public String getRefreshToken() {
  17. return refreshToken;
  18. }
  19. public void setRefreshToken(String refreshToken) {
  20. this.refreshToken = refreshToken;
  21. }
  22. public String getJti() {
  23. return jti;
  24. }
  25. public void setJti(String jti) {
  26. this.jti = jti;
  27. }
  28. }

UserJwt工具类

  1. package com.lpz.oauth.util;
  2. import org.springframework.security.core.GrantedAuthority;
  3. import org.springframework.security.core.userdetails.User;
  4. import java.util.Collection;
  5. public class UserJwt extends User {
  6. private String id; //用户ID
  7. private String name; //用户名字
  8. private String comny;//设置公司
  9. public UserJwt(String username, String password, Collection<? extends GrantedAuthority> authorities) {
  10. super(username, password, authorities);
  11. }
  12. public String getId() {
  13. return id;
  14. }
  15. public void setId(String id) {
  16. this.id = id;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. }

ResourceServerConfig(资源服务器上的配置类)

  1. package com.lpz.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.core.io.ClassPathResource;
  5. import org.springframework.core.io.Resource;
  6. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  7. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
  9. import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
  10. import org.springframework.security.oauth2.provider.token.TokenStore;
  11. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  12. import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
  13. import java.io.BufferedReader;
  14. import java.io.IOException;
  15. import java.io.InputStreamReader;
  16. import java.util.stream.Collectors;
  17. @Configuration
  18. @EnableResourceServer
  19. @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize注解
  20. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  21. //公钥
  22. private static final String PUBLIC_KEY = "public.key";
  23. /***
  24. * 定义JwtTokenStore
  25. * @param jwtAccessTokenConverter
  26. * @return
  27. */
  28. @Bean
  29. public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
  30. return new JwtTokenStore(jwtAccessTokenConverter);
  31. }
  32. /***
  33. * 定义JJwtAccessTokenConverter
  34. * @return
  35. */
  36. @Bean
  37. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  38. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  39. converter.setVerifierKey(getPubKey());
  40. return converter;
  41. }
  42. /**
  43. * 获取非对称加密公钥 Key
  44. *
  45. * @return 公钥 Key
  46. */
  47. private String getPubKey() {
  48. Resource resource = new ClassPathResource(PUBLIC_KEY);
  49. try {
  50. InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
  51. BufferedReader br = new BufferedReader(inputStreamReader);
  52. return br.lines().collect(Collectors.joining("\n"));
  53. } catch (IOException ioe) {
  54. return null;
  55. }
  56. }
  57. /***
  58. * Http安全配置,对每个到达系统的http请求链接进行校验
  59. * @param http
  60. * @throws Exception
  61. */
  62. @Override
  63. public void configure(HttpSecurity http) throws Exception {
  64. //所有请求必须认证通过
  65. http.authorizeRequests()
  66. //下边的路径放行
  67. .antMatchers(
  68. "/tbuser/info/**"). //配置地址放行
  69. permitAll()
  70. .anyRequest().
  71. authenticated(); //其他地址需要认证授权
  72. }
  73. }

gateway-server(全局过滤器代码)

  1. package com.lpz.filters;
  2. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  3. import org.springframework.cloud.gateway.filter.GlobalFilter;
  4. import org.springframework.core.Ordered;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.server.reactive.ServerHttpRequest;
  7. import org.springframework.http.server.reactive.ServerHttpResponse;
  8. import org.springframework.stereotype.Component;
  9. import org.springframework.util.StringUtils;
  10. import org.springframework.web.server.ServerWebExchange;
  11. import reactor.core.publisher.Mono;
  12. @Component
  13. public class PowerFilters implements GlobalFilter, Ordered {
  14. @Override
  15. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  16. ServerHttpRequest request = exchange.getRequest();
  17. ServerHttpResponse response = exchange.getResponse();
  18. String path = request.getURI().getPath();
  19. if (path.startsWith("/api/oauth/login")) {
  20. return chain.filter(exchange);
  21. }
  22. String token = request.getQueryParams().getFirst("token");
  23. if (StringUtils.isEmpty(token)) {
  24. token = request.getHeaders().getFirst("token");
  25. if (StringUtils.isEmpty(token)) {
  26. exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
  27. return exchange.getResponse().setComplete();
  28. }
  29. }
  30. request.mutate().header("Authorization", "bearer " + token);
  31. return chain.filter(exchange);
  32. }
  33. @Override
  34. public int getOrder() {
  35. return 0;
  36. }
  37. }

shop-oauth-server(AuthServiceImpl代码)

  1. package com.lpz.oauth.service.impl;
  2. import com.lpz.oauth.service.AuthService;
  3. import com.lpz.oauth.util.AuthToken;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.cloud.client.ServiceInstance;
  6. import org.springframework.cloud.client.discovery.DiscoveryClient;
  7. import org.springframework.http.HttpEntity;
  8. import org.springframework.http.HttpMethod;
  9. import org.springframework.http.ResponseEntity;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.util.Base64Utils;
  12. import org.springframework.util.LinkedMultiValueMap;
  13. import org.springframework.web.client.RestTemplate;
  14. import java.util.Base64;
  15. import java.util.List;
  16. import java.util.Map;
  17. @Service
  18. public class AuthServiceImpl implements AuthService {
  19. @Autowired
  20. private RestTemplate restTemplate;
  21. @Autowired
  22. private DiscoveryClient discoveryClient;
  23. @Override
  24. public AuthToken login(String username, String password, String clientId, String clientSecret) {
  25. List<ServiceInstance> instances = discoveryClient.getInstances("oauth-server");
  26. ServiceInstance serviceInstance = instances.get(0);
  27. String url = "http://" + serviceInstance.getHost()+":" + serviceInstance.getPort() + "/oauth/token";
  28. LinkedMultiValueMap<String, String> body = new LinkedMultiValueMap<>();
  29. body.add("grant_type", "password");
  30. body.add("username", username);
  31. body.add("password", password);
  32. LinkedMultiValueMap<String, String> head = new LinkedMultiValueMap<>();
  33. head.add("Authorization", myEncoder(clientId, clientSecret));
  34. ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(body, head), Map.class);
  35. Map map = response.getBody();
  36. System.out.println(map);
  37. AuthToken authToken = new AuthToken();
  38. authToken.setAccessToken(map.get("access_token").toString());
  39. authToken.setJti(map.get("jti").toString());
  40. authToken.setRefreshToken(map.get("refresh_token").toString());
  41. return authToken;
  42. }
  43. private static String myEncoder(String clientId, String clientSecret) {
  44. String code = clientId + ":" + clientId;
  45. byte[] encode = Base64Utils.encode(code.getBytes());
  46. return "Basic " + new String(encode);
  47. }
  48. public static void main(String[] args) {
  49. String s = myEncoder("changgou", "changgou");
  50. System.out.println(s);
  51. }
  52. }

4.资源服务授权流程

  1. 钥私钥授权流程

上图的业务流程如下:

  1. 客户端请求认证服务申请令牌
  2. 认证服务生成令牌认证服务采用非对称加密算法,使用私钥生成令牌。
  3. 客户端携带令牌访问资源服务客户端在Http header 中添加: Authorization:Bearer 令牌。
  4. 资源服务请求认证服务校验令牌的有效性资源服务接收到令牌,使用公钥校验令牌的合法性。
  5. 令牌有效,资源服务向客户端响应资源信息
2.公钥私钥

在对称加密的时代,加密和解密用的是同一个密钥,这个密钥既用于加密,又用于解密。这样做有一个明显的缺点,如果两个人之间传输文件,两个人都要知道密钥,如果是三个人呢,五个人呢?于是就产生了非对称加密,用一个密钥进行加密(公钥),用另一个密钥进行解密(私钥)。

总结:公钥加密、私钥解密、私钥签名、公钥验签。

3. 生成私钥公钥

Spring Security 提供对JWT的支持,本节我们使用Spring Security 提供的JwtHelper来创建JWT令牌,校验JWT令牌 等操作。 这里JWT令牌我们采用非对称算法进行加密,所以我们要先生成公钥和私钥。

(1)生成密钥证书 下边命令生成密钥证书,采用RSA 算法每个证书包含公钥和私钥

创建一个文件夹,在该文件夹下执行如下命令行:

keytool -genkeypair -alias qianggou -keyalg RSA -keypass qianggou -keystore qianggou.jks -storepass qianggou     

Keytool 是一个java提供的证书管理工具

  1. -alias:密钥的别名
  2. -keyalg:使用的hash算法
  3. -keypass:密钥的访问密码
  4. -keystore:密钥库文件名,qianggou.keystore保存了生成的证书
  5. -storepass:密钥库的访问密码

查询证书信息

keytool -list -keystore qianggou.jks

删除别名

keytool -delete -alias qianggou -keystore qianggou.jsk
4.导出公钥

openssl是一个加解密工具包,这里使用openssl来导出公钥信息。

安装 openssl:http://slproweb.com/products/Win32OpenSSL.html

安装资料目录下的Win64OpenSSL-1_1_0g.exe

配置openssl的path环境变量,如下图:

本教程配置在C:\OpenSSL-Win64\bin

cmd进入qianggou.jks文件所在目录执行如下命令(如下命令在windows下执行,会把-变成中文方式,请将它改成英文的-):

keytool -list -rfc --keystore qianggou.jks | openssl x509 -inform pem -pubkey

下面段内容是公钥

  1. -----BEGIN PUBLIC KEY-----
  2. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhTN8iyCyQEZPUmLw0GB0
  3. rH0xeT23w4c8X8thfEtphIBTAKOoUKHxhzBHra/WHLpPw/fV/m9KTvbWCdlBziKW
  4. r4P//KtUoa5D3qJupsPDxl9GTXJjG/9y/E+9hHLtl+cM2Qu+RTayFQ4X4ZqLjiOc
  5. lZZjN8g3MUomu45ab7PVJvuNUGcMq8s+pSvIwHQejYVKlPH8amSqyyxEyzH2MFBX
  6. N1c0KoerMfaDV0uzFCsUdOxUlpow9byCPZAspuNbN3DG3xwoHtOErWcchs8TlGMy
  7. So2QAeGADmCkH/iIHbF22ytmybIsbK5Ww9T+a1xK+wzzKBAucL+HuK5hLwQlSyuq
  8. zQIDAQAB
  9. -----END PUBLIC KEY-----

将上边的公钥拷贝到文本public.key文件中,合并为一行,可以将它放到需要实现授权认证的工程中。

5.运行图

在运行之前我们再来梳理一下流程

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

闽ICP备14008679号