千家信息网

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

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,小编给大家分享一下如何解决使用JWT作为Spring Security OAuth2的token存储问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!序Spring Security
千家信息网最后更新 2026年10月31日如何解决使用JWT作为Spring Security OAuth2的token存储问题

小编给大家分享一下如何解决使用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--对称加解密算法

授权服务器整体代码结构

pom.xml中引入依赖

            org.springframework.boot            spring-boot-starter-security            2.2.1.RELEASE                                                    org.springframework.security.oauth            spring-security-oauth3            2.4.0.RELEASE                            org.springframework.security            spring-security-jwt            1.1.0.RELEASE        

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转换器    }    /**     * jwt访问token转换器     */    @Bean    public JwtAccessTokenConverter jwtAccessTokenConverter(){        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        converter.setSigningKey("my-sign-key"); //资源服务器需要配置此选项方能解密jwt的token        return converter;    }    /**     * jwt的token存储对象     */    @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    }    /**     * jwt访问token转换器     */    @Bean    public JwtAccessTokenConverter jwtAccessTokenConverter(){        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        converter.setSigningKey("my-sign-key"); //与授权服务器相同的signingKey        return converter;    }    /**     * jwt的token存储对象     */    @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

返回结果

带token访问资源服务器

测试通过

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

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

服务 服务器 资源 配置 对称 算法 存储 方法 模式 目录 转换器 加密 测试 问题 相同 密钥 篇文章 部分 整合 生成 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技有限公司 互联网佳科技有限公司 互联网科技公司税收优惠 世界互联网领先科技成果 沃里互联网科技 互联网科技股午盘股票涨跌 互联网科技实习生岗位职责 以后互联网后是啥科技 移动互联网科技股 现代互联网科技股 语蝶互联网科技有限公司 深圳市优智互联网科技有限公司 亳州好赞互联网科技有限公司 乌苏新华互联网科技做什么的 黑科技 体验场景 互联网大会 互联网科技手机排行榜 科技信息时代互联网发展 保山浩联互联网科技有限公司 平安好医生打造互联网科技医疗 株洲百竞科技的互联网营销顾问 深圳恒合互联网络科技有限公司 科技企业和互联网企业 与互联网科技公司 北京互联网科技公司 致聘互联网科技 镁科技互联网资讯平台 互联网科技实习生岗位职责 湖北码尼互联网科技有限公司电话 互联网科技资金流入 互联网大会出现的黑科技
0