返回顶部
首页 > 资讯 > 精选 >如何解决使用JWT作为Spring Security OAuth2的token存储问题
  • 347
分享到

如何解决使用JWT作为Spring Security OAuth2的token存储问题

2023-06-22 05:06:05 347人浏览 八月长安
摘要

小编给大家分享一下如何解决使用Jwt作为spring Security OAuth2的token存储问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!序Spring Security OAuth3的de

小编给大家分享一下如何解决使用Jwt作为spring Security OAuth2的token存储问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

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

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

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

  • 使用JWT作为Token传递

  • 使用Redis存储Token,资源服务器本地访问Redis校验Token

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

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

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

授权服务器整体代码结构

如何解决使用JWT作为Spring Security OAuth2的token存储问题

pom.xml中引入依赖

<dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-security</artifactId>            <version>2.2.1.RELEASE</version>        </dependency>        <!-- Spring Security OAuth3 -->        <dependency>            <groupId>org.springframework.security.oauth</groupId>            <artifactId>spring-security-oauth3</artifactId>            <version>2.4.0.RELEASE</version>        </dependency>        <dependency>            <groupId>org.springframework.security</groupId>            <artifactId>spring-security-jwt</artifactId>            <version>1.1.0.RELEASE</version>        </dependency>

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

@Configuration@EnableWEBSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Bean    public AuthenticationManager authenticationManager() throws Exception {        return super.authenticationManager();    }    @Bean    public UserDetailsService userDetailsService(){ //主要是配置这个Bean,用于授权服务器配置中注入        return super.userDetailsService();    }    @Bean    public PassWordEncoder passwordEncoder(){        return new BCryptPasswordEncoder();    }    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        // @fORMatter: off        auth.inMemoryAuthentication()                .withUser("hellxz")                .password(passwordEncoder().encode("xyz"))                .authorities(Collections.emptyList());        // @formatter: on    }    @Override    protected void configure(httpsecurity Http) throws Exception {        http.authorizeRequests()                .anyRequest().authenticated() //所有请求都需要通过认证                .and()                .httpBasic() //Basic提交                .and()                .csrf().disable(); //关跨域保护    }}

授权服务器配置AuthorizationConfig

@Configuration@EnableAuthorizationServer //开启授权服务public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {    @Autowired    private AuthenticationManager authenticationManager;    @Autowired    public UserDetailsService userDetailsService;    @Autowired    private PasswordEncoder passwordEncoder;    @Override    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {        //允许表单提交        security.allowFormAuthenticationForClients()                .checkTokenAccess("permitAll()")                .tokenKeyAccess("permitAll()");    }    @Override    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {        // @formatter: off        clients.inMemory()                .withClient("client-a") //client端唯一标识                    .secret(passwordEncoder.encode("client-a-secret")) //client-a的密码,这里的密码应该是加密后的                    .authorizedGrantTypes("authorization_code", "password", "refresh_token") //授权模式标识,这里主要测试用password模式,另外refresh_token不是一种模式,但是可以使用它来刷新access_token(在它的有效期内)                    .scopes("read_user_info") //作用域                    .resourceIds("resource1") //资源id,如不需限制资源id,注释此处即可                    .redirectUris("http://localhost:9001/callback"); //回调地址        // @formatter: on    }    @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {        endpoints.authenticationManager(authenticationManager)                .userDetailsService(userDetailsService)                .tokenStore(jwtTokenStore()) //设置jwtToken为tokenStore                .accessTokenConverter(jwtAccessTokenConverter());//设置access_token转换器    }        @Bean    public JwtAccessTokenConverter jwtAccessTokenConverter(){        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        converter.setSigningKey("my-sign-key"); //资源服务器需要配置此选项方能解密jwt的token        return converter;    }        @Bean    public JwtTokenStore jwtTokenStore(){        return new JwtTokenStore(jwtAccessTokenConverter());    }}

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

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

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

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

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

@Configuration@EnableResourceServerpublic class ResourceConfig extends ResourceServerConfigurerAdapter {    @Bean    public PasswordEncoder passwordEncoder() {        return new BCryptPasswordEncoder();    }    @Override    public void configure(HttpSecurity http) throws Exception {        //设置创建session策略        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);        //@formatter:off        //所有请求必须授权        http.authorizeRequests()                .anyRequest().authenticated();        //@formatter:on    }    @Override    public void configure(ResourceServerSecurityConfigurer resources) {    //@formatter:off    //如不需要限制资源id,请在授权配置处去除resourceIds的配置    resources.resourceId("resource1")         .tokenStore(jwtTokenStore());    //@formatter:on    }        @Bean    public JwtAccessTokenConverter jwtAccessTokenConverter(){        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        converter.setSigningKey("my-sign-key"); //与授权服务器相同的signingKey        return converter;    }        @Bean    public JwtTokenStore jwtTokenStore(){        return new JwtTokenStore(jwtAccessTokenConverter());    }}

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

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

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

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

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

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

 @Bean    public JwtAccessTokenConverter jwtAccessTokenConverter(){        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        KeyStoreKeyFactory storeKeyFactory = new KeyStoreKeyFactory(                new ClassPathResource("hellxz-jwt.jks"), "hellxzTest".toCharArray());        converter.seTKEyPair(storeKeyFactory.getKeyPair("hellxz-jwt"));        return converter;    }

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

➜ keytool -list -rfc --keystore hellxz-jwt.jks | openssl x509 -inform pem -pubkey

输入密钥库口令:  hellxzTest

-----BEGIN PUBLIC KEY-----

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4

ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI

7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGGCe9tR0Q0iONcaN+b/lArK4T

Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzQt6fEPWqalBUVYdV0zCUDG8ikN1

l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+

0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh

zQIDAQAB

-----END PUBLIC KEY-----

-----BEGIN CERTIFICATE-----

MIIDUTCCAjmgAwIBAgIEePeDczANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJD

TjEQMA4GA1UECBMHYmVpamluZzEQMA4GA1UEBxMHYmVpamluZzEKMAgGA1UEChMB

MDEKMAgGA1UECxMBMDEOMAwGA1UEAxMFemhhbmcwHhcNMTkxMjE1MDUyOTM2WhcN

MjkxMjEyMDUyOTM2WjBZMQswCQYDVQQGEwJDTjEQMA4GA1UECBMHYmVpamluZzEQ

MA4GA1UEBxMHYmVpamluZzEKMAgGA1UEChMBMDEKMAgGA1UECxMBMDEOMAwGA1UE

AxMFemhhbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFTvO6UVRU

FeZkPbzHAzi6Xl73IWtOguBYoeU0uWn3Tj8ZuJYGhni1wFw2rdXEsYE31U6p8/U/

kLt9GDP3lQjtKEoIqCwUUYvasCqymUwMKU39p1+zGakXTqtUiQaBx721HRDSI41x

o35v+UCsrhMC7vpCxDCf0wteXOdV9zNyVk5lJ8M2O77Um4HOq3p8Q9apqUFRVh2X

TMJQMbyKQ3WX0PSbW1JJoqmJOtTbIRQZSOL7v1SvLtjwEKURfp3gJOX1NACEvmDf

YagkRzRLbL7Rup6pSy/WdS30qIlP2SI68D5DujZPw4e6pBP2V7uS+YiLiBJfm9I2

+9lqATZSCWHNAgMBAAGjITAfMB0GA1UdDgQWBBQF96rK7n0XufnvtJuH9tD9Ixza

6zANBgkqhkiG9w0BAQsFAAOCAQEAuMzWZJhej6+4TGgodQKQ5L5RBtOUbesxA1Ue

s9iA4m/jNZnVCXJE0nY47YVzBCIkIsYALswGooMj1PIJxEMpggXVmIuiJpaPgg+4

sthzISxKzX0ru8IrJTapaglMi74ai6S73LTBSke9GEPgWWnbtdUZoUSiSNt1oJ0J

EhFHdPuzxc36neDFRBOBxW4w3qhsTlKTN2wJm1nLV96nFKmqJhQJhhKt6ihe7hMg

qWxzNsWAqv9gJNdKZt5teqwNKT6H7r1NX5oJkJ0Kn1dZy0O3rDDD5E0KDKkMtwOh

3deJH6Uvtt/dw/drzJlByNDEPp6hYGQu2dW5JG5uiHuzFHnJeA==

-----END CERTIFICATE-----

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

-----BEGIN PUBLIC KEY-----

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4

ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI

7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGgce9tR0Q0iONcaN+b/lArK4T

Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzqt6fEPWqalBUVYdV0zCUDG8ikN1

l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+

0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh

zQIDAQAB

-----END PUBLIC KEY-----

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

  @Bean    public JwtAccessTokenConverter jwtAccessTokenConverter(){        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        Resource resource = new ClassPathResource("public.cert");        String publicKey;        try {            publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));        } catch (IOException e) {            throw new RuntimeException(e);        }        converter.setVerifierKey(publicKey);        return converter;    }

测试验证

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

如何解决使用JWT作为Spring Security OAuth2的token存储问题

返回结果

如何解决使用JWT作为Spring Security OAuth2的token存储问题

带token访问资源服务器

如何解决使用JWT作为Spring Security OAuth2的token存储问题

测试通过

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

看完了这篇文章,相信你对“如何解决使用JWT作为Spring Security OAuth2的token存储问题”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网精选频道,感谢各位的阅读!

--结束END--

本文标题: 如何解决使用JWT作为Spring Security OAuth2的token存储问题

本文链接: https://lsjlt.com/news/302669.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何解决使用JWT作为Spring Security OAuth2的token存储问题
    小编给大家分享一下如何解决使用JWT作为Spring Security OAuth2的token存储问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!序Spring Security OAuth3的de...
    99+
    2023-06-22
  • 使用JWT作为Spring Security OAuth2的token存储问题
    目录序授权服务器整合JWT——对称加解密算法资源服务器整合JWT——对称加解密算法OAuth整合JWT——非对称加解密RSA测试验证测试通过序 Spring Security OAu...
    99+
    2024-04-02
  • SpringBoot+Spring Security无法实现跨域的问题如何解决
    本篇内容主要讲解“SpringBoot+Spring Security无法实现跨域的问题如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot+Spring Security...
    99+
    2023-06-20
  • 如何解决Spring Security的权限配置不生效问题
    这篇文章主要介绍如何解决Spring Security的权限配置不生效问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Spring Security权限配置不生效在集成Spring Security做接口...
    99+
    2023-06-29
  • 如何解决spring-boot使用logback的问题
    这篇文章主要介绍了如何解决spring-boot使用logback的问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。用ConsoleAppender.java来举例,假设在...
    99+
    2023-06-20
  • 如何使用Python解决大数据存储和分析问题?
    随着互联网的不断发展,数据量也在不断增长。对于数据科学家和分析师来说,处理大量数据已经成为日常工作。Python作为一种高效且易学的编程语言,成为了大数据存储和分析的首选工具。本文将介绍如何使用Python解决大数据存储和分析问题。 一、...
    99+
    2023-10-28
    http 大数据 自然语言处理
  • 如何解决mysql存储过程太慢的问题
    小编给大家分享一下如何解决mysql存储过程太慢的问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!mysql存储过程太慢的解决...
    99+
    2024-04-02
  • MySQL如何解决无法存储emoji表情的问题
    这篇文章给大家分享的是有关MySQL如何解决无法存储emoji表情的问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体内容如下1. 在navicat中如果在新建表之前就改变数...
    99+
    2024-04-02
  • 如何解决java存储过程调用servlet的授权问题
    这篇文章给大家分享的是有关如何解决java存储过程调用servlet的授权问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。写了一个java存储过程,调用远端的servlet。在java程序和function均正...
    99+
    2023-06-03
  • 如何使用Spring解决ibatis多数据源的问题
    本篇内容介绍了“如何使用Spring解决ibatis多数据源的问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!iBatis多数据源的苦恼在...
    99+
    2023-06-18
  • Spring解决循环依赖问题及三级缓存的作用
    目录前言1什么是循环依赖2 如何解决循环依赖3无法解决的循环依赖前言 所谓的三级缓存只是三个可以当作是全局变量的Map,Spring的源码中大量使用了这种先将数据放入容器中等使用结束...
    99+
    2024-04-02
  • Security框架:如何使用CorsFilter解决前端跨域请求问题
    目录项目情况CORS介绍解决方案项目情况 最近做的pmdb项目是前后端分离的, 由于测试的时候是前端与后端联调,所以出现了跨域请求的问题。 浏览器默认会向后端发送一个Options方...
    99+
    2024-04-02
  • Spring使用三级缓存解决循环依赖的问题
    Spring如何使用三级缓存解决循环依赖在没开始文章之前首先来了解一下什么是循环依赖 @Component public class A { @Autowired ...
    99+
    2024-04-02
  • 如何解决MySQL存储时间类型选择的问题
    这篇文章主要为大家展示了“如何解决MySQL存储时间类型选择的问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决MySQL存储时间类型选择的问题”这篇文...
    99+
    2024-04-02
  • Python API的存储功能:如何解决重定向问题?
    在开发一个Web应用程序时,我们经常需要与外部的API进行交互,以获取所需的数据。Python提供了丰富的API库,例如Requests、urllib等,方便开发人员使用。但是,在使用API时,我们经常会遇到重定向问题,这会导致一些不必要...
    99+
    2023-09-13
    api 重定向 存储
  • 如何解决overlay2存储驱动的磁盘配额问题
    这篇文章主要为大家展示了“如何解决overlay2存储驱动的磁盘配额问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决overlay2存储驱动的磁盘配额问题”这篇文章吧。为啥要用over...
    99+
    2023-06-04
  • 如何解决PHP开发中的存储和缓存一致性问题
    在PHP开发中,存储和缓存是常见的数据处理方式。然而,存储和缓存的不一致性可能会导致错误的数据结果,从而影响系统的可靠性和性能。为了解决这个问题,我们可以采取一些措施来确保存储和缓存的一致性。一、使用事务处理事务是一组操作的集合,可以被看作...
    99+
    2023-10-21
    PHP开发 缓存一致性 存储问题
  • 如何解决spring boot项目使用@JsonFormat失效问题
    这篇文章给大家分享的是有关如何解决spring boot项目使用@JsonFormat失效问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。使用@JsonFormat失效在实体类定义时间格式原因:项目中配置了fa...
    99+
    2023-06-25
  • 如何在LeetCode上使用Spring框架来解决问题?
    LeetCode是一个广受欢迎的在线编程平台,许多开发者都会在上面挑战自己的编程能力。Spring框架则是一个流行的Java开发框架,它提供了许多实用的工具和功能,可以帮助开发者更快地构建高效的应用程序。那么,如何在LeetCode上使用S...
    99+
    2023-10-21
    二维码 spring leetcode
  • 如何解决MySQL存储时间出现不一致的问题
    小编给大家分享一下如何解决MySQL存储时间出现不一致的问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!用Java在获取了系统时间后,存入MySQL数据库时,当时间的类型为datetime或Timestamp时发现数据库...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作