Spring Security OAuth2的demo在前几篇文章中已经讲过了,在那些模式中使用的都是RemoteTokenService调用授权服务器来校验token,返回校验通过的用户信息供上下文中获取

这种方式会加重授权服务器的负载,你想啊,当用户没授权时候获取token得找授权服务器,有token了访问资源服务器还要访问授权服务器,相当于说每次请求都要访问授权服务器,这样对授权服务器的负载会很大

常规的方式有两种来解决这个问题:

  1. 使用JWT作为Token传递
  2. 使用Redis存储Token,资源服务器本地访问Redis校验Token

使用JWT与Redis都可以在资源服务器中进行校验Token,从而减少授权服务器的工作量

JWT默认使用HMACSHA256对称加密算法,以下记录下默认算法实现与非对称RSA算法的集成,使用不同算法加解密测试方法是一致的,所以放在文章最后

授权服务器整合JWT——对称加解密算法

授权服务器整体代码结构

pom.xml中引入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. <version>2.2.1.RELEASE</version>
  5. </dependency>
  6. <!-- Spring Security OAuth2 -->
  7. <dependency>
  8. <groupId>org.springframework.security.oauth</groupId>
  9. <artifactId>spring-security-oauth2</artifactId>
  10. <version>2.4.0.RELEASE</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.security</groupId>
  14. <artifactId>spring-security-jwt</artifactId>
  15. <version>1.1.0.RELEASE</version>
  16. </dependency>

SecurityConfig配置,主要需要显式声明AuthenticationManager和UserDetailsService这两个bean

  1. @Configuration
  2. @EnableWebSecurity
  3. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  4. @Bean
  5. public AuthenticationManager authenticationManager() throws Exception {
  6. return super.authenticationManager();
  7. }
  8. @Bean
  9. public UserDetailsService userDetailsService(){ //主要是配置这个Bean,用于授权服务器配置中注入
  10. return super.userDetailsService();
  11. }
  12. @Bean
  13. public PasswordEncoder passwordEncoder(){
  14. return new BCryptPasswordEncoder();
  15. }
  16. @Override
  17. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  18. // @formatter: off
  19. auth.inMemoryAuthentication()
  20. .withUser("hellxz")
  21. .password(passwordEncoder().encode("xyz"))
  22. .authorities(Collections.emptyList());
  23. // @formatter: on
  24. }
  25. @Override
  26. protected void configure(HttpSecurity http) throws Exception {
  27. http.authorizeRequests()
  28. .anyRequest().authenticated() //所有请求都需要通过认证
  29. .and()
  30. .httpBasic() //Basic提交
  31. .and()
  32. .csrf().disable(); //关跨域保护
  33. }
  34. }

授权服务器配置AuthorizationConfig

  1. @Configuration
  2. @EnableAuthorizationServer //开启授权服务
  3. public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
  4. @Autowired
  5. private AuthenticationManager authenticationManager;
  6. @Autowired
  7. public UserDetailsService userDetailsService;
  8. @Autowired
  9. private PasswordEncoder passwordEncoder;
  10. @Override
  11. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  12. //允许表单提交
  13. security.allowFormAuthenticationForClients()
  14. .checkTokenAccess("permitAll()")
  15. .tokenKeyAccess("permitAll()");
  16. }
  17. @Override
  18. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  19. // @formatter: off
  20. clients.inMemory()
  21. .withClient("client-a") //client端唯一标识
  22. .secret(passwordEncoder.encode("client-a-secret")) //client-a的密码,这里的密码应该是加密后的
  23. .authorizedGrantTypes("authorization_code", "password", "refresh_token") //授权模式标识,这里主要测试用password模式,另外refresh_token不是一种模式,但是可以使用它来刷新access_token(在它的有效期内)
  24. .scopes("read_user_info") //作用域
  25. .resourceIds("resource1") //资源id
  26. .redirectUris("http://localhost:9001/callback"); //回调地址
  27. // @formatter: on
  28. }
  29. @Override
  30. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  31. endpoints.authenticationManager(authenticationManager)
  32. .userDetailsService(userDetailsService)
  33. .tokenStore(jwtTokenStore()) //设置jwtToken为tokenStore
  34. .accessTokenConverter(jwtAccessTokenConverter());//设置access_token转换器
  35. }
  36. /**
  37. * jwt访问token转换器
  38. */
  39. @Bean
  40. public JwtAccessTokenConverter jwtAccessTokenConverter(){
  41. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  42. converter.setSigningKey("my-sign-key"); //资源服务器需要配置此选项方能解密jwt的token
  43. return converter;
  44. }
  45. /**
  46. * jwt的token存储对象
  47. */
  48. @Bean
  49. public JwtTokenStore jwtTokenStore(){
  50. return new JwtTokenStore(jwtAccessTokenConverter());
  51. }
  52. }

这里主要是在configure(AuthorizationServerEndpointsConfigurer endpoints)授权服务的端点配置中加入JWT的tokenStore和access_token的转换器,以及这二者的声明Bean方法

这里使用的是默认对称MAC算法,即加密解密使用相同的密钥

启动类就不说了,开启@SpringBootApplicatin的main方法

资源服务器整合JWT——对称加解密算法

资源服务器主要就一个资源配置类

  1. @Configuration
  2. @EnableResourceServer
  3. public class ResourceConfig extends ResourceServerConfigurerAdapter {
  4. @Bean
  5. public PasswordEncoder passwordEncoder() {
  6. return new BCryptPasswordEncoder();
  7. }
  8. @Override
  9. public void configure(HttpSecurity http) throws Exception {
  10. //设置创建session策略
  11. http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
  12. //@formatter:off
  13. //所有请求必须授权
  14. http.authorizeRequests()
  15. .anyRequest().authenticated();
  16. //@formatter:on
  17. }
  18. @Override
  19. public void configure(ResourceServerSecurityConfigurer resources) {
  20. resources.tokenStore(jwtTokenStore());
  21. }
  22. /**
  23. * jwt访问token转换器
  24. */
  25. @Bean
  26. public JwtAccessTokenConverter jwtAccessTokenConverter(){
  27. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  28. converter.setSigningKey("my-sign-key"); //与授权服务器相同的signingKey
  29. return converter;
  30. }
  31. /**
  32. * jwt的token存储对象
  33. */
  34. @Bean
  35. public JwtTokenStore jwtTokenStore(){
  36. return new JwtTokenStore(jwtAccessTokenConverter());
  37. }
  38. }

配置JWT的TokenStore和AccessTokenConverter与授权服器相同,添加启动类完成配置

OAuth整合JWT——非对称加解密RSA

本部分基于对称加密部分,仅展示需要修改的部分

首先使用keytool生成jks (Java Key Store) 密钥,按提示输入姓氏等信息

  1. keytool -genkeypair -alias hellxz-jwt -validity 3650 -keyalg RSA -keypass hellxzTest -keystore hellxz-jwt.jks -storepass hellxzTest

生成的私钥文件会在当前目录,把hellxz-jwt.jks复制到授权服务器的resources目录下

授权服务器需修改jwtAccessTokenConverter()

  1. @Bean
  2. public JwtAccessTokenConverter jwtAccessTokenConverter(){
  3. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  4. KeyStoreKeyFactory storeKeyFactory = new KeyStoreKeyFactory(
  5. new ClassPathResource("hellxz-jwt.jks"), "hellxzTest".toCharArray());
  6. converter.setKeyPair(storeKeyFactory.getKeyPair("hellxz-jwt"));
  7. return converter;
  8. }

在hellxz-jwt.jks同目录下,执行命令生成公钥

  1. keytool -list -rfc --keystore hellxz-jwt.jks | openssl x509 -inform pem -pubkey
  2. 输入密钥库口令: hellxzTest
  3. -----BEGIN PUBLIC KEY-----
  4. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4
  5. ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI
  6. 7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGgce9tR0Q0iONcaN+b/lArK4T
  7. Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzqt6fEPWqalBUVYdV0zCUDG8ikN1
  8. l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+
  9. 0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh
  10. zQIDAQAB
  11. -----END PUBLIC KEY-----
  12. -----BEGIN CERTIFICATE-----
  13. MIIDUTCCAjmgAwIBAgIEePeDczANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJD
  14. TjEQMA4GA1UECBMHYmVpamluZzEQMA4GA1UEBxMHYmVpamluZzEKMAgGA1UEChMB
  15. MDEKMAgGA1UECxMBMDEOMAwGA1UEAxMFemhhbmcwHhcNMTkxMjE1MDUyOTM2WhcN
  16. MjkxMjEyMDUyOTM2WjBZMQswCQYDVQQGEwJDTjEQMA4GA1UECBMHYmVpamluZzEQ
  17. MA4GA1UEBxMHYmVpamluZzEKMAgGA1UEChMBMDEKMAgGA1UECxMBMDEOMAwGA1UE
  18. AxMFemhhbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFTvO6UVRU
  19. FeZkPbzHAzi6Xl73IWtOguBYoeU0uWn3Tj8ZuJYGhni1wFw2rdXEsYE31U6p8/U/
  20. kLt9GDP3lQjtKEoIqCwUUYvasCqymUwMKU39p1+zGakXTqtUiQaBx721HRDSI41x
  21. o35v+UCsrhMC7vpCxDCf0wteXOdV9zNyVk5lJ8M2O77Um4HOq3p8Q9apqUFRVh1X
  22. TMJQMbyKQ3WX0PSbW1JJoqmJOtTbIRQZSOL7v1SvLtjwEKURfp3gJOX1NACEvmDf
  23. YagkRzRLbL7Rup6pSy/WdS30qIlP2SI68D5DujZPw4e6pBP2V7uS+YiLiBJfm9I2
  24. +9lqATZSCWHNAgMBAAGjITAfMB0GA1UdDgQWBBQF96rK7n0XufnvtJuH9tD9Ixza
  25. 6zANBgkqhkiG9w0BAQsFAAOCAQEAuMzWZJhej6+4TGgodQKQ5L5RBtOUbesxA1Ue
  26. s9iA4m/jNZnVCXJE0nY47YVzBCIkIsYALswGooMj1PIJxEMpggXVmIuiJpaPgg+4
  27. sthzISxKzX0ru8IrJTapaglMi74ai6S73LTBSke9GEPgWWnbtdUZoUSiSNt1oJ0J
  28. EhFHdPuzxc36neDFRBOBxW4w3qhsTlKTN2wJm1nLV96nFKmqJhQJhhKt6ihe7hMg
  29. qWxzNsWAqv9gJNdKZt5teqwNKT6H7r1NX5oJkJ0Kn1dZy0O3rDDd5E0KDKkMtwOh
  30. 3deJH6Uvtt/dw/drzJlByNDEPp6hYGQu2dW5JG5uiHuzFHnJeA==
  31. -----END CERTIFICATE-----

复制公钥部分到public.cert放到资源服务器的resources目录

  1. -----BEGIN PUBLIC KEY-----
  2. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4
  3. ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI
  4. 7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGgce9tR0Q0iONcaN+b/lArK4T
  5. Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzqt6fEPWqalBUVYdV0zCUDG8ikN1
  6. l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+
  7. 0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh
  8. zQIDAQAB
  9. -----END PUBLIC KEY-----

修改资源服务器jwtAccessTokenConverter()方法

  1. @Bean
  2. public JwtAccessTokenConverter jwtAccessTokenConverter(){
  3. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  4. Resource resource = new ClassPathResource("public.cert");
  5. String publicKey;
  6. try {
  7. publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
  8. } catch (IOException e) {
  9. throw new RuntimeException(e);
  10. }
  11. converter.setVerifierKey(publicKey);
  12. return converter;
  13. }

测试验证

发送POST请求http://localhost:8080/oauth/token?username=hellxz&password=xyz&scope=read_user_info&grant_type=password

返回结果

带token访问资源服务器

测试通过

另外使用JWT应设置尽量短的过期时间,因为JWT的token无法手动revoke,只能等待其到达过期时间失效

使用JWT作为Spring Security OAuth2的token存储的更多相关文章

  1. 使用Redis作为Spring Security OAuth2的token存储

    写在前边 本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快, ...

  2. Spring Security Oauth2 使用 token 访问资源服务器出现异常:Invalid token does not contain resource id (oauth2)

    异常如图 查看资源服务器的日志 p.a.OAuth2AuthenticationProcessingFilter : Authentication request failed: error=&quo ...

  3. Spring Security OAuth2.0认证授权五:用户信息扩展到jwt

    历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...

  4. Spring Security OAuth2.0认证授权六:前后端分离下的登录授权

    历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...

  5. Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战

    一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...

  6. spring security oauth2 client_credentials模

    spring security oauth2 client_credentials模 https://www.jianshu.com/p/1c3eea71410e 序 本文主要简单介绍一下spring ...

  7. spring security oauth2 搭建认证中心demo

    oauth2 介绍 ​ oauth2 协议应该是开发者们耳熟能详的协议了,这里就不做过多的介绍了,具体介绍如何在spring security中搭建oauth2的认证服务.Spring-Securit ...

  8. spring security oauth2搭建resource-server demo及token改造成JWT令牌

    我们在上文讲了如何在spring security的环境中搭建基于oauth2协议的认证中心demo:https://www.cnblogs.com/process-h/p/15688971.html ...

  9. spring security oauth2 jwt 认证和资源分离的配置文件(java类配置版)

    最近再学习spring security oauth2.下载了官方的例子sparklr2和tonr2进行学习.但是例子里包含的东西太多,不知道最简单最主要的配置有哪些.所以决定自己尝试搭建简单版本的例 ...

随机推荐

  1. NOI2019退役记 upd:2019.12.1

    (我把原来写的东西全部删掉了) AFO. 我退役了,\(\mbox{yyb}\)退役了. 至少,在接下来的日子里,我得投身到文化课,度过快乐的高三生活了. 这两年的\(OI\)生涯给了我很多,让我学会 ...

  2. JVM GC系列 — GC收集器

    一.前言 前文学习了各种GC回收算法,掌握了GC回收的原理,但是真正的GC实现却尤为复杂,本篇文章将主要介绍各种GC收集器. 目前主流的HotSpot VM支持多种虚拟机,这些虚拟机也体现了GC的发展 ...

  3. Solr java.sql.SQLException: null, message from server: "Host 'xxx' is not allowed to connect to this MySQL server

    在用solr从mysql导入数据的时候,因为linux和本机的数据库不在同一个ip段上, 又因为本地的mysql没有设置远程其它ip可以访问所以就报了如下错误 解决办法: 在mysql任意可以输入查询 ...

  4. MySQL问题记录——导入导出权限设置

    MySQL问题记录——导入导出权限设置 摘要:本文主要记录了在使用MySQL的过程中导入导出权限设置时遇到的问题以及解决方案. 相关日志 [Note] --secure-file-priv is se ...

  5. Java 小游戏 - 井字棋 v1.0 (初步完成) (2018.4.16更新)

      井字棋游戏初步完成 实现功能:输入位置数据->打印棋盘->判断是否胜利->继续游戏/退出游戏 缺点:没有清屏函数   判断胜利方法太过无脑    package MYGAME; ...

  6. 顺F速运国际版,你的密码漏点了

    - 加密情况分析 对APP的分析过程,当然首先是安装,使用,抓包啦. 同样地,登录,抓包看看. 使用账号密码登录. - 壳呢? 虽然直接解密了顺F国际版的加密数据,但还是有必要看看它的APK. 经过分 ...

  7. 【React Native】日常踩坑记录_以后将持续更新

    作为一名有理想.有抱负的一代iOS程序员,本着“我头发够多,还能学”的原则,我选择了追随那些大佬的脚步,于2018年开始了React Native. 第一步:找文档.准备安装开发环境: 第二步:一步步 ...

  8. MBProgressHUD源码(上)

    本篇博文记录MBProgressHUD源码学习过程,从官方提供的Demo项目入手,一步步了解其代码结构,学习它使用的技术,体会作者的编程思想. 一.结构 我们先来看下MBProgressHUD的结构, ...

  9. flask接收跨域请求

    ajax发送数据类型为json即可 接受数据详见下文 https://www.cnblogs.com/anxminise/p/9814326.html

  10. centos7中python3.6报错ModuleNotFoundError: No module named '_ssl' 或者 Max retries exceeded with url: / (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.",))

    如果在运行爬虫时报此错:requests.exceptions.SSLError: HTTPSConnectionPool(host='www.baidu.com', port=443): Max r ...