Spring Boot 实现权限管理(下)

方案2:Spring Boot + Spring Security + JWT

从第一种方法你们肯定已经看出来了,权限控制的核心就是获取当前用户所拥有的权限,只要我们提供用户数据来源可以不实现 UserDetailsService,所以就有了这第二种方法的JWT。

(1)添加依赖 首先需要在 pom.xml 文件中添加 io.jsonwebtoken 库的依赖:

xml 复制代码
<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>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

(2)创建 JWT 工具类

java 复制代码
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtUtil {

    // 密钥,用于签名和验证 JWT,应妥善保管
    private static final String SECRET_KEY = "yourSecretKey";
    // JWT 的过期时间,这里设置为 10 小时
    private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 10;

    // 根据用户详细信息生成 JWT
    // 这里的userDetails可以是你自己定义的用户类
    public String generateToken(UserDetails userDetails) {
        //自定义的声明
        Map<String, Object> claims = new HashMap<>();
        //鉴权所需的权限角色
        //userDetails.getIdentities()是List<String>的角色字符串列表
        claims.put("identities",userDetails.getIdentities());
        return createToken(claims, userDetails.getId());
    }

    // 创建 JWT 的具体方法
    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
               .setClaims(claims)//自定义的声明
               .setSubject(subject)//存的用户id
               .setIssuedAt(new Date(System.currentTimeMillis()))
               .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
               .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
               .compact();
    }


    //解析jwt
    public Claims extractAllClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(SECRET_KEY)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}    

(3)创建TokenFilter 创建TokenFilter过滤器来验证并解析jwt,从而获取权限信息

java 复制代码
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        //获取token
        final String authorizationHeader = request.getHeader("Authorization");
        // 没有带token直接过去
        if(authorizationHeader == null){
            chain.doFilter(request, response);
        }
        //解析token
        String jwt = null;
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            Claims claims;
            try {
                claims = jwtUtil.extractAllClaims(jwt);
            } catch (IllegalArgumentException e) {
                //解析 JWT 时发生其他错误
                System.out.println("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                //JWT 已过期
                System.out.println("JWT Token has expired");
            }
        }
        //取出权限角色列表
        Object identitiesObj = claims.get("identities");
        List<GrantedAuthority> authorities = new ArrayList<>();
        if (identitiesObj instanceof List) {
            List<?> identitiesList = (List<?>) identitiesObj;
            for (Object obj : identitiesList) {
                if (obj instanceof String) {
                    authorities.add(new SimpleGrantedAuthority((String) obj));
                }
            }
        }
        String userId = claims.getSubject();
        //将 Authentication 对象设置到 SecurityContextHolder 中后,Spring Security 就能在后续的授权过程中使用这些权限信息了。
        Authentication authentication = new UsernamePasswordAuthenticationToken(userId, null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }
}

(4)配置 Spring Security

java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login", "/public/​**​").permitAll()  // 公开接口
                .requestMatchers("/user/​**​").hasAuthority("user") // 需具体权限
                .anyRequest().authenticated()                         // 其他接口需登录
            )

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();  // 密码加密
    }
}

现在就实现jwt的权限管理了。

对比2种方法总结:​​ ​​✅ 优点​​ ​​灵活性高​​:角色和权限可动态配置。 ​​易于扩展​​:支持方法级和 URL 级权限控制。 ​​适合单体应用​​:数据库存储权限,管理方便。 ​​❌ 缺点​​ ​​微服务架构下重复鉴权​​:每个服务需单独校验权限(可结合 ​​Gateway + JWT​​ 优化)。

相关推荐
Flynt4 分钟前
我试了Spring Boot 4的原生镜像,聊聊那些数字和坑
java·spring boot
凤山老林7 分钟前
复杂检索引擎落地:Spring Boot + Elasticsearch 数据同步与高阶查询实战
spring boot·后端·elasticsearch
M-Robots echo7 小时前
轻量化裁剪方案解析:M-Robots 模块化构建,适配高低端各类机器人硬件平台
java·机器人·ros·开源社区·atomgit·m-robots
笃行3508 小时前
SQLServer数据迁移之后,那张报表还能不能秒出
后端
不可求~8 小时前
多模型路由怎么落地:把任务分流写进项目的最小实现
java·前端·数据库
LucianaiB8 小时前
别再被 AI 骗了:我把腾讯云 4 个 Skill 做成了个「AI 打假侦探」,过程的一个小配置坑惨了我
后端
mldong9 小时前
用 DDD 设计工作流引擎:聚合根与充血模型
java·架构
candyTong9 小时前
Claude Code 如何恢复一段会话
后端·架构·ai编程
mqiqe10 小时前
AgentScope Java Harness:4. 双层记忆系统 让 Agent 拥有真正的“长期大脑“
java·开发语言
伍一5110 小时前
03-文件管理模块-一个看似简单的模块藏着多少细节
java·ruoyi·若依