当前位置:   article > 正文

springCloud之OAuth2_spring-cloud-starter-oauth2

spring-cloud-starter-oauth2

认证授权过程

在认证和授权的过程中涉及的三方包括:

1、服务提供方,用户使用服务提供方来存储受保护的资源,如照片,视频,联系人列表。

2、用户,存放在服务提供方的受保护的资源的拥有者。

3、客户端,要访问服务提供方资源的第三方应用,通常是网站,如提供照片打印服务的网站。在认证过程之前,客户端要向服务提供者申请客户端标识。

使用OAuth进行认证和授权的过程如下所示:

用户想操作存放在服务提供方的资源。

用户登录客户端向服务提供方请求一个临时令牌。

服务提供方验证客户端的身份后,授予一个临时令牌。

客户端获得临时令牌后,将用户引导至服务提供方的授权页面请求用户授权。在这个过程中将临时令牌和客户端的回调连接发送给服务提供方。

用户在服务提供方的网页上输入用户名和密码,然后授权该客户端访问所请求的资源。

授权成功后,服务提供方引导用户返回客户端的网页。

客户端根据临时令牌从服务提供方那里获取访问令牌

服务提供方根据临时令牌和用户的授权情况授予客户端访问令牌。

客户端使用获取的访问令牌访问存放在服务提供方上的受保护的资源。

一、服务端搭建

项目结构

1、依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-security</artifactId>
  8. </dependency>
  9. <!-- OAuth2.0依赖,不再内置了,所以得我们自己指定一下版本 -->
  10. <dependency>
  11. <groupId>org.springframework.cloud</groupId>
  12. <artifactId>spring-cloud-starter-oauth2</artifactId>
  13. <version>2.2.5.RELEASE</version>
  14. </dependency>

2、配置文件

  1. package com.minos.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.security.authentication.AuthenticationManager;
  4. import org.springframework.security.core.userdetails.UserDetailsService;
  5. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  6. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  7. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  8. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  9. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  10. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  11. import javax.annotation.Resource;
  12. @EnableAuthorizationServer //开启验证服务器
  13. @Configuration
  14. public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
  15. @Resource
  16. private AuthenticationManager manager;
  17. @Resource
  18. UserDetailsService service;
  19. private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  20. /**
  21. * 这个方法是对客户端进行配置,一个验证服务器可以预设很多个客户端,
  22. * 之后这些指定的客户端就可以按照下面指定的方式进行验证
  23. * @param clients 客户端配置工具
  24. */
  25. @Override
  26. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  27. clients
  28. .inMemory() //这里我们直接硬编码创建,当然也可以像Security那样自定义或是使用JDBC从数据库读取
  29. .withClient("web") //客户端名称,随便起就行
  30. .secret(encoder.encode("654321")) //只与客户端分享的secret,随便写,但是注意要加密
  31. .autoApprove(false) //自动审批,这里关闭,要的就是一会体验那种感觉
  32. .scopes("book", "user", "borrow") //授权范围,这里我们使用全部all
  33. .redirectUris("http://localhost:8201/login") //可以写多个,当有多个时需要在验证请求中指定使用哪个地址进行回调
  34. .authorizedGrantTypes("client_credentials", "password", "implicit", "authorization_code", "refresh_token");
  35. //授权模式,一共支持5种,除了之前我们介绍的四种之外,还有一个刷新Token的模式
  36. //这里我们直接把五种都写上,方便一会实验,当然各位也可以单独只写一种一个一个进行测试
  37. //现在我们指定的客户端就支持这五种类型的授权方式了
  38. }
  39. @Override
  40. public void configure(AuthorizationServerSecurityConfigurer security) {
  41. security
  42. .passwordEncoder(encoder) //编码器设定为BCryptPasswordEncoder
  43. .allowFormAuthenticationForClients() //允许客户端使用表单验证,一会我们POST请求中会携带表单信息
  44. .checkTokenAccess("permitAll()"); //允许所有的Token查询请求
  45. }
  46. @Override
  47. public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
  48. endpoints
  49. .authenticationManager(manager);
  50. //由于SpringSecurity新版本的一些底层改动,这里需要配置一下authenticationManager,才能正常使用password模式
  51. endpoints
  52. .userDetailsService(service);
  53. }
  54. }
  1. package com.minos.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.authentication.AuthenticationManager;
  5. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  6. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  7. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  8. import org.springframework.security.core.userdetails.UserDetailsService;
  9. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  10. @Configuration
  11. public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  12. @Override
  13. protected void configure(HttpSecurity http) throws Exception {
  14. http
  15. .authorizeRequests()
  16. .anyRequest().authenticated() //
  17. .and()
  18. .formLogin().permitAll(); //使用表单登录
  19. }
  20. @Override
  21. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  22. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  23. auth
  24. .inMemoryAuthentication() //直接创建一个用户,懒得搞数据库了
  25. .passwordEncoder(encoder)
  26. .withUser("test").password(encoder.encode("123456")).roles("USER");
  27. }
  28. @Bean //这里需要将AuthenticationManager注册为Bean,在OAuth配置中使用
  29. @Override
  30. public AuthenticationManager authenticationManagerBean() throws Exception {
  31. return super.authenticationManagerBean();
  32. }
  33. @Bean
  34. @Override
  35. public UserDetailsService userDetailsServiceBean() throws Exception {
  36. return super.userDetailsServiceBean();
  37. }
  38. }
  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. @SpringBootApplication
  4. public class AuthApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(AuthApplication.class,args);
  7. }
  8. }

3、配置属性

  1. server:
  2. port: 8500
  3. servlet:
  4. #为了防止一会在服务之间跳转导致Cookie打架(因为所有服务地址都是localhost,都会存JSESSIONID)
  5. #这里修改一下context-path,这样保存的Cookie会使用指定的路径,就不会和其他服务打架了
  6. #但是注意之后的请求都得在最前面加上这个路径
  7. context-path: /sso

二、服务端测试

1、客户端模式

  1. http://localhost:8500/sso/oauth/token
  2. grant_type:client_credentials
  3. client_id:web
  4. client_secret:654321

验证token

http://localhost:8500/sso/oauth/check_token?token=7cd6c753-bd1f-4a41-aa60-372dc43f2a70

 

2、密码模式

  1. http://localhost:8500/sso/oauth/token
  2. grant_type:password
  3. username:test
  4. password:123456

 填写请求参数

 设置校验账号密码

 3、隐式授权模式

浏览器调用

http://localhost:8500/sso/oauth/authorize?client_id=web&response_type=token

 服务器根据规则携带token重定向至http://localhost:8201/login

http://localhost:8201/login#access_token=2d81d2ff-898f-4138-bc0b-a46c2c15a13c&token_type=bearer&expires_in=42373&scope=book%20borrow%20user

 4、授权码模式

http://localhost:8500/sso/oauth/authorize?client_id=web&response_type=code

 浏览器页面登录

 

 勾选权限

 

 返回code

http://localhost:8201/login?code=4om04n

 根据返回code获取token

  1. http://localhost:8500/sso/oauth/token
  2. grant_type:authorization_code
  3. client_id:web
  4. client_secret:654321
  5. code:4om04n

 5、刷新token

  1. http://localhost:8500/sso/oauth/token
  2. grant_type:refresh_token
  3. client_id:web
  4. client_secret:654321
  5. refresh_token:b1eda2a0-d1bd-4bd3-9c48-67115e159bf2

三、基于@EnableOAuth2Sso实现自动登录

1、导入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.cloud</groupId>
  7. <artifactId>spring-cloud-starter-oauth2</artifactId>
  8. <version>2.2.5.RELEASE</version>
  9. </dependency>

2、启动类添加开启注解

@EnableOAuth2Sso

 3、配置文件增加配置

  1. security:
  2. oauth2:
  3. client:
  4. #不多说了
  5. client-id: web
  6. client-secret: 654321
  7. #Token获取地址
  8. access-token-uri: http://localhost:8500/sso/oauth/token
  9. #验证页面地址
  10. user-authorization-uri: http://localhost:8500/sso/oauth/authorize
  11. resource:
  12. #Token信息获取和校验地址
  13. token-info-uri: http://localhost:8500/sso/oauth/check_token

四、基于@EnableResourceServer实现资源服务器

 1、导入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.cloud</groupId>
  7. <artifactId>spring-cloud-starter-oauth2</artifactId>
  8. <version>2.2.5.RELEASE</version>
  9. </dependency>

2、启动类添加开启注解

@EnableResourceServer

 3、配置文件增加配置

  1. security:
  2. oauth2:
  3. client:
  4. #不多说了
  5. client-id: web
  6. client-secret: 654321
  7. resource:
  8. #Token信息获取和校验地址
  9. token-info-uri: http://localhost:8500/sso/oauth/check_token

4、权限范围校验

  1. @Configuration
  2. public class ResourceConfiguration extends ResourceServerConfigurerAdapter { //继承此类进行高度自定义
  3. @Override
  4. public void configure(HttpSecurity http) throws Exception { //这里也有HttpSecurity对象,方便我们配置SpringSecurity
  5. http
  6. .authorizeRequests()
  7. .anyRequest().access("#oauth2.hasScope('lbwnb')"); //添加自定义规则
  8. //Token必须要有我们自定义scope授权才可以访问此资源
  9. }
  10. }

5、RestTemplate 远程调用携带token

  1. @Configuration
  2. public class WebConfiguration {
  3. @Resource
  4. OAuth2ClientContext context;
  5. @Bean
  6. public OAuth2RestTemplate restTemplate(){
  7. return new OAuth2RestTemplate(new ClientCredentialsResourceDetails(), context);
  8. }
  9. }

 使用OAuth2RestTemplate进行调用,自动携带token

  1. @Resource
  2. OAuth2RestTemplate template;

6、Feign调用携带token

OpenFeign使用参考。

https://blog.csdn.net/qq_29752857/article/details/129221077
  1. feign:
  2. oauth2:
  3. #开启Oauth支持,这样就会在请求头中携带Token了
  4. enabled: true
  5. #同时开启负载均衡支持
  6. load-balanced: true

7、使用JWT

服务端配置

  1. @Bean
  2. public JwtAccessTokenConverter tokenConverter(){ //Token转换器,将其转换为JWT
  3. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  4. converter.setSigningKey("lbwnb"); //这个是对称密钥,一会资源服务器那边也要指定为这个
  5. return converter;
  6. }
  7. @Bean
  8. public TokenStore tokenStore(JwtAccessTokenConverter converter){ //Token存储方式现在改为JWT存储
  9. return new JwtTokenStore(converter); //传入刚刚定义好的转换器
  10. }
  1. @Resource
  2. TokenStore store;
  3. @Resource
  4. JwtAccessTokenConverter converter;
  5. private AuthorizationServerTokenServices serverTokenServices(){ //这里对AuthorizationServerTokenServices进行一下配置
  6. DefaultTokenServices services = new DefaultTokenServices();
  7. services.setSupportRefreshToken(true); //允许Token刷新
  8. services.setTokenStore(store); //添加刚刚的TokenStore
  9. services.setTokenEnhancer(converter); //添加Token增强,其实就是JwtAccessTokenConverter,增强是添加一些自定义的数据到JWT中
  10. return services;
  11. }
  12. @Override
  13. public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
  14. endpoints
  15. .tokenServices(serverTokenServices()) //设定为刚刚配置好的AuthorizationServerTokenServices
  16. .userDetailsService(service)
  17. .authenticationManager(manager);
  18. }

客户端配置,jwt的密钥和服务端配置一样

  1. security:
  2. oauth2:
  3. resource:
  4. jwt:
  5. key-value: lbwnb #注意这里要跟验证服务器的密钥一致,这样算出来的签名才会一致

服务端完整配置

  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.security.authentication.AuthenticationManager;
  3. import org.springframework.security.core.userdetails.UserDetailsService;
  4. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  5. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  6. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  7. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  8. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  9. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  10. import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
  11. import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
  12. import org.springframework.security.oauth2.provider.token.TokenStore;
  13. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  14. import javax.annotation.Resource;
  15. @EnableAuthorizationServer //开启验证服务器
  16. @Configuration
  17. public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
  18. @Resource
  19. private AuthenticationManager manager;
  20. @Resource
  21. UserDetailsService service;
  22. @Resource
  23. TokenStore store;
  24. @Resource
  25. JwtAccessTokenConverter converter;
  26. private AuthorizationServerTokenServices serverTokenServices(){ //这里对AuthorizationServerTokenServices进行一下配置
  27. DefaultTokenServices services = new DefaultTokenServices();
  28. services.setSupportRefreshToken(true); //允许Token刷新
  29. services.setTokenStore(store); //添加刚刚的TokenStore
  30. services.setTokenEnhancer(converter); //添加Token增强,其实就是JwtAccessTokenConverter,增强是添加一些自定义的数据到JWT中
  31. return services;
  32. }
  33. private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  34. /**
  35. * 这个方法是对客户端进行配置,一个验证服务器可以预设很多个客户端,
  36. * 之后这些指定的客户端就可以按照下面指定的方式进行验证
  37. *
  38. * @param clients 客户端配置工具
  39. */
  40. @Override
  41. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  42. clients
  43. .inMemory() //这里我们直接硬编码创建,当然也可以像Security那样自定义或是使用JDBC从数据库读取
  44. .withClient("web") //客户端名称,随便起就行
  45. .secret(encoder.encode("654321")) //只与客户端分享的secret,随便写,但是注意要加密
  46. .autoApprove(false) //自动审批,这里关闭,要的就是一会体验那种感觉
  47. .scopes("book", "user", "borrow") //授权范围,这里我们使用全部all
  48. .redirectUris("http://localhost:8500/login") //可以写多个,当有多个时需要在验证请求中指定使用哪个地址进行回调
  49. .authorizedGrantTypes("client_credentials", "password", "implicit", "authorization_code", "refresh_token");
  50. //授权模式,一共支持5种,除了之前我们介绍的四种之外,还有一个刷新Token的模式
  51. //这里我们直接把五种都写上,方便一会实验,当然各位也可以单独只写一种一个一个进行测试
  52. //现在我们指定的客户端就支持这五种类型的授权方式了
  53. }
  54. @Override
  55. public void configure(AuthorizationServerSecurityConfigurer security) {
  56. security
  57. .passwordEncoder(encoder) //编码器设定为BCryptPasswordEncoder
  58. .allowFormAuthenticationForClients() //允许客户端使用表单验证,一会我们POST请求中会携带表单信息
  59. .checkTokenAccess("permitAll()"); //允许所有的Token查询请求
  60. }
  61. @Override
  62. public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
  63. endpoints
  64. .tokenServices(serverTokenServices()) //设定为刚刚配置好的AuthorizationServerTokenServices
  65. .authenticationManager(manager);
  66. //由于SpringSecurity新版本的一些底层改动,这里需要配置一下authenticationManager,才能正常使用password模式
  67. endpoints
  68. .userDetailsService(service);
  69. }
  70. }
  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.security.authentication.AuthenticationManager;
  4. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  5. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  7. import org.springframework.security.core.userdetails.UserDetailsService;
  8. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  9. import org.springframework.security.oauth2.provider.token.TokenStore;
  10. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  11. import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
  12. @Configuration
  13. public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  14. @Override
  15. protected void configure(HttpSecurity http) throws Exception {
  16. http
  17. .authorizeRequests()
  18. .anyRequest().authenticated() //
  19. .and()
  20. .formLogin().permitAll(); //使用表单登录
  21. }
  22. @Override
  23. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  24. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  25. auth
  26. .inMemoryAuthentication() //直接创建一个用户,懒得搞数据库了
  27. .passwordEncoder(encoder)
  28. .withUser("test").password(encoder.encode("123456")).roles("USER");
  29. }
  30. @Bean //这里需要将AuthenticationManager注册为Bean,在OAuth配置中使用
  31. @Override
  32. public AuthenticationManager authenticationManagerBean() throws Exception {
  33. return super.authenticationManagerBean();
  34. }
  35. @Bean
  36. @Override
  37. public UserDetailsService userDetailsServiceBean() throws Exception {
  38. return super.userDetailsServiceBean();
  39. }
  40. @Bean
  41. public JwtAccessTokenConverter tokenConverter(){ //Token转换器,将其转换为JWT
  42. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  43. converter.setSigningKey("lbwnb"); //这个是对称密钥,一会资源服务器那边也要指定为这个
  44. return converter;
  45. }
  46. @Bean
  47. public TokenStore tokenStore(JwtAccessTokenConverter converter){ //Token存储方式现在改为JWT存储
  48. return new JwtTokenStore(converter); //传入刚刚定义好的转换器
  49. }
  50. }

测试数据 

  1. {
  2. "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2Nzg0NTU5NzUsInVzZXJfbmFtZSI6InRlc3QiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOWU1YWQ1YzQtMGMzYS00ZDk1LWJkMzAtYTRjNWIxYTJjYjQwIiwiY2xpZW50X2lkIjoid2ViIiwic2NvcGUiOlsiYm9vayIsInVzZXIiLCJib3Jyb3ciXX0.usX2dEmo33RIKFsavHYISxsZ90egECJxnmGrGBRz1ZM",
  3. "token_type": "bearer",
  4. "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ0ZXN0Iiwic2NvcGUiOlsiYm9vayIsInVzZXIiLCJib3Jyb3ciXSwiYXRpIjoiOWU1YWQ1YzQtMGMzYS00ZDk1LWJkMzAtYTRjNWIxYTJjYjQwIiwiZXhwIjoxNjgxMDA0Nzc1LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiZDc5OGQxNWYtNmNlNi00ZmVmLTlhYmEtZTk0MWU4ODBhMWM4IiwiY2xpZW50X2lkIjoid2ViIn0.puqEiGA27R1DTQiRk7WQ6OIYhGJ0i87AkrRHK1G5dkA",
  5. "expires_in": 43199,
  6. "scope": "book user borrow",
  7. "jti": "9e5ad5c4-0c3a-4d95-bd30-a4c5b1a2cb40"
  8. }

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

闽ICP备14008679号