SpringSecurity的TokenStore四種實現(xiàn)方式小結
什么是Token Store
在Web開發(fā)中,Token Store 通常用于存儲用戶身份驗證令牌(Tokens),例如 JSON Web Tokens (JWT) 或其他形式的令牌。這些令牌可以用于驗證用戶身份,實現(xiàn)用戶會話管理以及訪問控制。
一種簡單的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
實現(xiàn),包括內存中存儲、JDBC 數據庫存儲和基于 JWT(JSON Web Token)的存儲。下面將分別介紹這三種實現(xiàn)方式,并提供基本的代碼示例。
1. 內存中存儲(In-Memory)
這個是OAuth2默認采用的實現(xiàn)方式。在單服務上可以體現(xiàn)出很好特效(即并發(fā)量不大,并且它在失敗的時候不會進行備份),大多項目都可以采用此方法。根據名字就知道了,是存儲在內存中,畢竟存在內存,而不是磁盤中,調試簡易。但是,實際中很少使用,因為沒有持久化,會導致數據丟失。
@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的實現(xiàn),令牌(Access Token)會保存到數據庫。這個方式,可以在多個服務之間實現(xiàn)令牌共享。因為是保存到數據庫,而且是必須有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。這個實現(xiàn)方式不用管如何進行存儲(內存或磁盤),因為它可以把相關信息數據編碼存放在令牌里。JwtTokenStore 不會保存任何數據,但是它在轉換令牌值以及授權信息方面與 DefaultTokenServices 所扮演的角色是一樣的。
既然jwt是將信息存放在令牌中,那么就得考慮其安全性,因此,OAuth2提供了JwtAccessTokenConverter實現(xiàn),添加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實現(xiàn)方式。具體包括內存中存儲、JDBC數據庫存儲、保存到redis和基于JWT的存儲。每個實現(xiàn)方式都涉及到授權服務器的配置,用于管理和驗證令牌,以及客戶端詳情的配置。
到此這篇關于SpringSecurity的TokenStore四種實現(xiàn)方式小結的文章就介紹到這了,更多相關SpringSecurity TokenStore內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于@EnableGlobalMethodSecurity注解的用法解讀
這篇文章主要介紹了關于@EnableGlobalMethodSecurity注解的用法解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03如何優(yōu)雅的實現(xiàn)將Collection轉為Map
這篇文章主要介紹了如何優(yōu)雅的實現(xiàn)將Collection轉為Map,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03