SpringSecurity升级之后token刷新接口401

在自定义的认证服务器配置类中添加如下内容

@Override
@SuppressWarnings("deprecation")
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
   
   
    security.tokenKeyAccess("permitAll()");
    security.
<think>好的,我现在要解决用户的问题:如何在Spring Security 6中结合JWT实现RBAC,并完成用户密码的数据库验证。首先,我需要理清楚整个流程,确保每一步都正确无误。 首先,用户提到了Spring Security 6,JWT,RBAC以及数据库验证。这些都是关键点。我需要回忆一下Spring Security的最新版本的变化,尤其是从Spring Security 56升级可能带来的变化,比如配置类的调整,过时方法的替换等。 接下来,RBAC模型的实现。RBAC通常涉及用户、角色、权限这三个核心实体,用户属于角色,角色拥有权限。数据库设计方面,可能需要用户表、角色表、权限表,以及它们之间的关联表。例如,用户角色是多对多,角色权限也是多对多。需要确认这些表的结构,并确保Spring Security能正确读取这些信息。 然后是JWT的集成。JWT用于无状态认证,所以在用户登录后生成token,后续请求携带这个token进行验证。需要创建JWT的工具类,处理生成解析token的逻辑。同时,需要自定义一个过滤器,在Spring Security的过滤器链中加入JWT的验证逻辑,替换原有的Session机制。 数据库验证用户密码这部分,Spring Security默认使用内存验证,但用户需要的是数据库验证。因此,需要配置UserDetailsService接口的实现类,从数据库中查询用户信息,并比对密码。这里需要注意密码的加密存储,Spring Security推荐使用BCryptPasswordEncoder,所以在保存用户密码时需要加密,验证时自动解密。 接下来是具体的步骤。首先,项目依赖的配置。Spring Security 6可能需要最新的Spring Boot版本,所以需要检查pom.xml或build.gradle中的依赖是否正确,特别是Spring SecurityJWT相关的库,如jjwt。 然后,实体类数据库表的设计。用户表需要包含用户名、密码、是否启用等字段,角色表有角色名称,权限表有权限名称,中间表处理多对多关系。可能需要使用JPA或者MyBatis来操作数据库,这里用户可能用的是JPA,因为Spring Data JPASpring Boot集成较好。 接着是UserDetailsService的实现。这个类需要重写loadUserByUsername方法,从数据库查询用户信息,包括对应的角色权限。这里需要注意,角色权限可能需要转换为Spring Security的GrantedAuthority对象,通常是在前面加ROLE_前缀或者直接作为权限字符串。 然后是JWT的生成验证工具类。需要处理token的签名、过期时间、主题等信息。生成token时使用密钥进行签名,验证时解析token并检查签名是否有效。密钥需要妥善保存,可能存储在配置文件中。 接下来是过滤器的编写。这个过滤器需要拦截每个请求,检查是否有合法的JWT token。如果存在且有效,则从中提取用户信息,并设置到SecurityContextHolder中,这样后续的权限验证就可以正常进行。这里要注意过滤器的顺序,确保它在Spring Security的认证过滤器之前执行。 配置SecurityFilterChain是Spring Security 6中的新方式,替代了之前的WebSecurityConfigurerAdapter。需要配置哪些路径需要认证,哪些可以匿名访问,关闭CSRFSession管理,因为使用无状态的JWT。同时,要添加自定义的JWT过滤器到过滤器链中。 密码加密方面,必须使用PasswordEncoder,推荐BCrypt。在用户注册时,密码需要经过加密再存储到数据库。在认证时,Spring Security会自动处理密码的比对,无需手动解密。 测试部分,需要确保登录接口能够生成token,其他接口在携带token时能够正确访问,否则返回401。同时,不同角色的用户访问权限受限的接口时,是否正确返回403或其他错误码。 可能遇到的问题包括:依赖版本冲突,JWT签名密钥配置错误,过滤器配置顺序不当导致未生效,数据库查询用户时出现的异常(如用户不存在),密码未加密存储导致验证失败,权限未正确加载等。需要逐一排查,查看日志,使用调试工具验证每一步是否正确。 最后,参考用户提供的引用内容,特别是引用[1][2],里面提到了一些实现细节,比如如何重写UsernamePasswordAuthenticationFilter,配置HttpSecurity,以及使用数据库认证的数据表设计。需要确保这些内容与Spring Security 6的最新配置方法兼容,例如使用Lambda DSL配置权限,而不是旧版的antMatchers方式。 总结整个流程,步骤大致如下:配置依赖,设计数据库实体,实现UserDetailsService,创建JWT工具类过滤器,配置SecurityFilterChain,处理密码加密,编写登录接口生成token,测试验证。每一步都需要仔细检查,确保符合Spring Security 6的要求,特别是配置类的新写法。</think>以下是在Spring Security 6中结合JWT实现RBAC并完成数据库密码验证的完整实现方案: --- ### 一、项目依赖配置(pom.xml) ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> ``` --- ### 二、数据库设计(RBAC模型) ```sql CREATE TABLE users ( id BIGINT PRIMARY KEY, username VARCHAR(50) UNIQUE, password VARCHAR(100), enabled BOOLEAN ); CREATE TABLE roles ( id BIGINT PRIMARY KEY, name VARCHAR(20) UNIQUE ); CREATE TABLE permissions ( id BIGINT PRIMARY KEY, name VARCHAR(50) UNIQUE ); CREATE TABLE user_roles ( user_id BIGINT, role_id BIGINT, PRIMARY KEY(user_id, role_id) ); CREATE TABLE role_permissions ( role_id BIGINT, permission_id BIGINT, PRIMARY KEY(role_id, permission_id) ); ``` --- ### 三、核心实现步骤 #### 1. 实现UserDetailsService ```java @Service public class JpaUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.getEnabled(), true, true, true, getAuthorities(user.getRoles()) ); } private Collection<? extends GrantedAuthority> getAuthorities(Set<Role> roles) { return roles.stream() .flatMap(role -> role.getPermissions().stream()) .map(permission -> new SimpleGrantedAuthority(permission.getName())) .collect(Collectors.toList()); } } ``` #### 2. JWT工具类 ```java public class JwtUtils { private static final String SECRET_KEY = "your-256-bit-secret"; private static final long EXPIRATION = 86400000; // 24小时 public static String generateToken(UserDetails user) { return Jwts.builder() .setSubject(user.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public static String extractUsername(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody() .getSubject(); } } ``` #### 3. JWT认证过滤器 ```java public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String token = resolveToken(request); if (token != null && validateToken(token)) { Authentication auth = getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(auth); } chain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } } ``` #### 4. 安全配置类 ```java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/login").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` --- ### 四、密码验证流程 1. 用户提交`username``password`到`/api/auth/login` 2. 服务端通过`UserDetailsService`验证数据库凭证 3. 验证成功后生成JWT令牌返回给客户端 4. 客户端后续请求携带`Authorization: Bearer <token>`头部 5. 过滤器解析并验证令牌有效性 --- ### 五、关键优化点 1. **动态权限控制**:通过`@PreAuthorize("hasAuthority('PERMISSION_NAME')")`注解实现方法级权限控制 2. **令牌刷新机制**:当令牌快过期时返回新令牌 3. **黑名单管理**:使用Redis记录失效的令牌 --- 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值