开发者

Spring Security+JWT如何实现前后端分离权限控制

目录
  • Spring Security+JWT实现前后端分离权限控制实战
    • 一、为什么要用 JWT?
    • 二、JWT 基本结构
    • 三、集成 JWT 的 Spring Security 权限控制思路
    • 四、核心模块代码实战
    • 五、前端如何配合使用?
    • 六、权限控制示例
  • 总结

    Spring Security+JWT实现前后端分离权限控制实战

    在前后端分离项目中,传统的基于 Session 的认证方式已不再适用。取而代之的是更加轻量、高效的 JWT(jsON Web Token)方式来实现无状态认证。

    一、为什么要用 JWT?

    前后端分离架构的挑战:

    • 无法使用 Session 管理登录状态(前端和后端分离、跨域)
    • 需要一种「无状态认证机制

    JWT 的优势:

    • 无需在服务端存储会话信息(Token 自包含)
    • 结构清晰,支持权限声明(claims)
    • 可扩展性强,可用于 OAuth、SSO 等场景

    二、JWT 基本结构

    一个 JWT Token 一般分为三段:

    Header.Payload.Signature

    例如:

    eyJhbGciOiJIUzI1NiJ9.eyJzdwIiOiJ1c2VyIiwiaWF0IjoxNjg3NjQ5fQ.K4KgD1sE0JQzA1K6k-FaSd56fQ

    每部分作用:

    部分内容
    Header签名算法,如 HS256
    Payload载荷(如用户名、角色、过期时间)
    Signature签名(防止篡改)

    三、集成 JWT 的 Spring Security 权限控制思路

    整体流程如下:

    前端登录 -> 后端验证用户 -> 生成 JWT -> 返回给前端 -> 前端每次请求携带 Token -> 后端解析验证并授权

    四、核心模块代码实战

    1. 引入依赖(Spring Boot 3.x 示例)

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

    2. JWT 工具类

    @Component
    public class JwtUtil {
        private final String SECRET = "MyJwtSecretKey123"; // 建议放到配置文件中
        private final long EXPIRATION = 1000 * 60 * 60; // 1小时
    
        public String generateToken(String username) {
            return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(SignatureAlgorithm.HS256, SECRET)
                .compact();
        }
    
        public String getUsernameFromToken(String token) {
            return Jwts.parser().setSigningKey(SECRET)
                .parseClaimsJws(token).getBody().getSubject();
        }
    
        public boolean validateToken(String token) {
            try {
                Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }

    3. 自定义登录接口生成 Token

    @RestController
    public class AuthController {
    
        @Autowired
        private AuthenticationManager authenticationManager;
    
        @Autowired
        private JwtUtil jwtUtil;
    
        @PostMapping("/login")
        public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
            try {
                Authentication auth = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(loginRequest.ge编程客栈tUsername(), loginRequest.getPassword())
                );
                String token = jwtUtil.generateToken(loginRequest.getUsername());
                return ResponseEntity.ok(Collections.singletonMap("token", token));
            } catch (AuthenticationException e) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
            }
        }
    }

    4. JWT 认证过滤php器

    @Component
    public class JwtAuthFilter extends OncePerRequestFilter {
    
        @Autowired
        private JwtUtil jwtUtil;
    
        @Autowired
        private UserDetailsService userDetailsService;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
                throws ServletException, IOException {
            String authHeader = request.getHeader("Authorization");
    
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                String token = authHeader.substring(7);
                String username = jwtUtil.getUsernameFromToken(token);
    
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
    
                    if (jwtUtil.validateToken(token)) {
                        UsernamePasswordAuthenticationToken authToken =
                            new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
    
                        authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authToken);
                    }
                }
            }
    
            chain.doFilter(request, response);
        }
    }

    5. 配置 SecurityFilterChain

    @Configuration
    @EnajsbleMethovoTMkPdSecurity
    public class SecurityConfig {
    
        @Autowired
        private JwtAuthFilter jwtAuthFilter;
    
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            return http
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/login").permitAll()
                    .anyRequest().authenticated()
                )
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
        }
    
        @Bean
        public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
            return config.getAuthenticationManager();
        }
    }

    五、前端如何配合使用?

    1. 登录后保存返回的 token
    2. 所有后续请求在 header 中添加:
    Authorization: Bearer <你的 token>

    六、权限控制示例

    @RestController
    public class UserController {
    
        @PreAuthorize("hasRole('ADMIN')")
        @GetMapping("/admin/data")
        public String adminData() {
            return "管理员数据";
        }
    
        @PreAuthorize("hasAnyRole('USER','ADMIN')")
        @GetMapping("/user/data")
        public String userData() {
            return "用户数据";
       python }
    }

    总结

    JWT 与 Spring Security 的结合,可以帮助你构建一个无状态、安全、高效的前后端分离权限系统。它简化了登录状态的管理流程,提高了系统的伸缩性与并发处理能力。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜