SpringSecurity的TokenStore四种实现方式小结

 更新时间:2024年01月30日 09:50:56   作者:Javaesandyou  
本文主要介绍了SpringSecurity的TokenStore四种实现方式小结,分别是InMemoryTokenStore,JdbcTokenStore,JwkTokenStore,RedisTokenStore,具有一定的参考价值,感兴趣的可以了解一下

什么是Token Store

在Web开发中,Token Store 通常用于存储用户身份验证令牌(Tokens),例如 JSON Web Tokens (JWT) 或其他形式的令牌。这些令牌可以用于验证用户身份,实现用户会话管理以及访问控制。

一种简单的Token Store示例,使用Node.js和Express框架以及一个基于内存的Token存储方式:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();
app.use(express.json());

// In-memory Token Store
const tokenStore = {};

// Secret key for JWT (replace with a strong, secret key in production)
const secretKey = 'your_secret_key';

// Middleware to verify JWT
function verifyToken(req, res, next) {
    const token = req.headers.authorization;

    if (!token) {
        return res.status(403).json({ message: 'No token provided' });
    }

    jwt.verify(token, secretKey, (err, decoded) => {
        if (err) {
            return res.status(401).json({ message: 'Failed to authenticate token' });
        }

        req.user = decoded;
        next();
    });
}

// Endpoint to generate and return a JWT
app.post('/login', (req, res) => {
    const { username, password } = req.body;

    // Authenticate user (replace with your actual authentication logic)
    // For simplicity, assume any username and password combination is valid
    const user = { username, role: 'user' };

    // Generate a JWT
    const token = jwt.sign(user, secretKey, { expiresIn: '1h' });

    // Store the token in memory
    tokenStore[token] = user;

    res.json({ token });
});

// Protected endpoint that requires a valid JWT for access
app.get('/protected', verifyToken, (req, res) => {
    res.json({ message: 'This is a protected endpoint', user: req.user });
});

// Start the server
const port = 3000;
app.listen(port, () => {
    console.log(`Server is running on http://localhost:${port}`);
});

 Spring Security 提供了几个常见的 TokenStore 实现,包括内存中存储、JDBC 数据库存储和基于 JWT(JSON Web Token)的存储。下面将分别介绍这三种实现方式,并提供基本的代码示例。

1. 内存中存储(In-Memory) 

这个是OAuth2默认采用的实现方式。在单服务上可以体现出很好特效(即并发量不大,并且它在失败的时候不会进行备份),大多项目都可以采用此方法。根据名字就知道了,是存储在内存中,毕竟存在内存,而不是磁盘中,调试简易。但是,实际中很少使用,因为没有持久化,会导致数据丢失。

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Bean
    public TokenStore inMemoryTokenStore() {
        return new InMemoryTokenStore();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
            .inMemory()
            .withClient("client")
            .secret("{noop}secret")  // 使用 "{noop}" 表示不加密
            .authorizedGrantTypes("password", "authorization_code", "refresh_token")
            .scopes("read", "write")
            .accessTokenValiditySeconds(3600)
            .refreshTokenValiditySeconds(86400);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .tokenStore(inMemoryTokenStore())
            .authenticationManager(authenticationManager);
    }
}

2. JDBC 数据库存储

这个是基于JDBC的实现,令牌(Access Token)会保存到数据库。这个方式,可以在多个服务之间实现令牌共享。因为是保存到数据库,而且是必须有OAuth2默认的表结构:oauth_access_token。

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private DataSource dataSource;

    @Bean
    public TokenStore jdbcTokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
            .jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .tokenStore(jdbcTokenStore())
            .authenticationManager(authenticationManager);
    }
}

3. 基于 JWT 的存储

jwt全称 JSON Web Token。这个实现方式不用管如何进行存储(内存或磁盘),因为它可以把相关信息数据编码存放在令牌里。JwtTokenStore 不会保存任何数据,但是它在转换令牌值以及授权信息方面与 DefaultTokenServices 所扮演的角色是一样的。

既然jwt是将信息存放在令牌中,那么就得考虑其安全性,因此,OAuth2提供了JwtAccessTokenConverter实现,添加jwtSigningKey,以此生成秘钥,以此进行签名,只有jwtSigningKey才能获取信息。

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Value("${security.jwt.client-id}")
    private String clientId;

    @Value("${security.jwt.client-secret}")
    private String clientSecret;

    @Value("${security.jwt.grant-type}")
    private String grantType;

    @Value("${security.jwt.scope-read}")
    private String scopeRead;

    @Value("${security.jwt.scope-write}")
    private String scopeWrite;

    @Value("${security.jwt.resource-ids}")
    private String resourceIds;

    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("secret");
        return converter;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
            .inMemory()
            .withClient(clientId)
            .secret("{noop}" + clientSecret)
            .authorizedGrantTypes(grantType)
            .scopes(scopeRead, scopeWrite)
            .resourceIds(resourceIds);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .tokenStore(jwtTokenStore())
            .accessTokenConverter(jwtAccessTokenConverter())
            .authenticationManager(authenticationManager);
    }
}

4.RedisTokenStore

顾名思义,就是讲令牌信息存储到redis中。首先必须保证redis连接正常。

@Autowired
private RedisConnectionFactory redisConnectionFactory;
/**
 * redis token 配置
 */
@Bean
public TokenStore redisTokenStore() {
    return new RedisTokenStore(redisConnectionFactory);
}


@Autowired(required = false)
private TokenStore redisTokenStore;
/**
 * 端点(处理入口)
 */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   endpoints.tokenStore(redisTokenStore);
   ....
}

小结

我们介绍了Spring Security中四种不同的Token Store实现方式。具体包括内存中存储、JDBC数据库存储、保存到redis和基于JWT的存储。每个实现方式都涉及到授权服务器的配置,用于管理和验证令牌,以及客户端详情的配置。

到此这篇关于SpringSecurity的TokenStore四种实现方式小结的文章就介绍到这了,更多相关SpringSecurity TokenStore内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IDEA设置JVM运行参数的方法步骤

    IDEA设置JVM运行参数的方法步骤

    这篇文章主要介绍了IDEA设置JVM运行参数的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • PowerJob的OhMyClassLoader工作流程源码解读

    PowerJob的OhMyClassLoader工作流程源码解读

    这篇文章主要介绍了PowerJob的OhMyClassLoader工作流程源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Java实现根据图片url下载图片并动态添加水印

    Java实现根据图片url下载图片并动态添加水印

    这篇文章主要为大家详细介绍了如何使用Java实现根据图片url下载图片并动态添加水印,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2026-01-01
  • 一文搞懂Spring Security异常处理机制

    一文搞懂Spring Security异常处理机制

    这篇文章主要为大家详细介绍一下Spring Security异常处理机制,文中的示例代码讲解详细,对我们学习Spring Security有一定帮助,感兴趣的可以学习一下
    2022-07-07
  • 解决java中的父类私有成员变量的继承问题

    解决java中的父类私有成员变量的继承问题

    这篇文章主要介绍了解决java中的父类私有成员变量的继承问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 一篇文章掌握Java Thread的类及其常见方法

    一篇文章掌握Java Thread的类及其常见方法

    Thread类用于操作线程,是所以涉及到线程操作(如并发)的基础。本文将通过代码对Thread类的功能作用及其常见方法进行分析
    2022-03-03
  • Java中Stream流对多个字段进行排序的方法

    Java中Stream流对多个字段进行排序的方法

    我们在处理数据的时候经常会需要进行排序后再返回给前端调用,比如按照时间升序排序,前端展示数据就是按时间先后进行排序,下面这篇文章主要给大家介绍了关于Java中Stream流对多个字段进行排序的相关资料,需要的朋友可以参考下
    2023-10-10
  • Java实现微信扫码登入的实例代码

    Java实现微信扫码登入的实例代码

    这篇文章主要介绍了java实现微信扫码登入功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • MyBatis基于pagehelper实现分页原理及代码实例

    MyBatis基于pagehelper实现分页原理及代码实例

    这篇文章主要介绍了MyBatis基于pagehelper实现分页原理及代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Java中自己如何实现log2(N)

    Java中自己如何实现log2(N)

    这篇文章主要介绍了Java中自己实现log2(N)的方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论