spring security redis
时间: 2025-01-09 21:39:15 浏览: 4
### Spring Security 集成 Redis 实现会话管理与认证授权
#### 1. 添加依赖项
为了使项目能够使用 Spring Security 和 Redis,需要在 `pom.xml` 文件中添加必要的 Maven 依赖。
```xml
<dependencies>
<!-- Spring Boot Starter Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Lettuce 连接池 (默认配置) -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
<!-- JSON Web Token 支持 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
</dependencies>
```
#### 2. 配置 Redis 连接工厂
通过自定义 Bean 来覆盖默认的连接设置,确保应用程序能正确访问到 Redis 数据库实例。
```java
@Configuration
public class RedisConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory();
}
}
```
#### 3. 设置 Session 存储位置为 Redis
修改 application.properties 或者 yml 文件来指定 session 的存储方式:
```properties
server.servlet.session.timeout=86400 # 单位秒,一天有效期
spring.redis.host=localhost # Redis服务器地址
spring.redis.port=6379 # Redis端口号
spring.session.store-type=redis # 使用Redis作为session仓库
```
#### 4. 自定义 UserDetailsService 接口实现类
创建一个服务组件用于加载用户特定数据,并返回 UserDetails 对象给框架处理验证逻辑。
```java
@Service
public class CustomUserDetailService implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
public CustomUserDetailService(UserRepository userRepository){
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<UserEntity> userOpt = userRepository.findByUsername(username);
if (!userOpt.isPresent()) throw new UsernameNotFoundException("Invalid username or password.");
UserEntity user = userOpt.get();
Set<GrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority(user.getRole().name()));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
authorities
);
}
}
```
#### 5. 创建 JWT 工具类
编写工具方法来进行 token 的生成和解析操作。
```java
@Component
public class JwtUtil {
private static final String SECRET_KEY = "secret";
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 有效时间十分钟
.signWith(SignatureAlgorithm.HS256, SECRET_KEY.getBytes())
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (
username.equals(userDetails.getUsername())
&& !isTokenExpired(token));
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
try{
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY.getBytes())
.build()
.parseClaimsJws(token)
.getBody();
}catch(Exception e){
System.out.println(e.getMessage());
return null;
}
}
}
```
#### 6. 构建过滤器链并注册至安全上下文中
最后一步是在全局范围内应用这些更改,即向 HTTP 请求管道注入新的身份验证机制。
```java
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
private final JwtRequestFilter jwtRequestFilter;
@Autowired
public SecurityConfigurer(JwtRequestFilter jwtRequestFilter) {this.jwtRequestFilter = jwtRequestFilter;}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService()).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public CustomUserDetailService customUserDetailService(){
return new CustomUserDetailService(null); // 此处应传入实际的服务层对象
}
@Bean
public JwtRequestFilter authenticationJwtTokenFilter(){
return new Jwt
阅读全文