Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南

2025-11-27 19:50

本文主要是介绍Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《SpringBoot基于JWT优化SpringSecurity无状态登录实战指南》本文介绍如何使用JWT优化SpringSecurity实现无状态登录,提高接口安全性,并通过实际操作步骤...

Spring Boot 实战:基于 JWT 优化 Spring Security 无状态登录

在上一篇文章中,我们通过 Spring Security 实现了基础的接口权限控制,但采用的 HTTP Basic 登录存在明显缺陷:安全,用户名和密码只是简单的通过 Base64 编码之后就开始传送了,很容易被破解,进而暴露用户信息。

本文将引入 JWT(jsON Web Token) 技术,重构登录流程,让接口即安全又贴合企业级项目需求。

一、先搞懂:为什么需要 JWT?

Jwt的核心优势是 无状态

  • 登录成功后,服务器生成一个包含用户信息和权限的加密 Token,直接返回给客户端;
  • 客户端后续请求时,只需在请求头携带 Token,服务器无需存储任何状态,直接通过 Token 验证身份和权限;
  • 多台服务器共用一套 Token 验证逻辑,无需同步状态,完美适配分布式部署。

二、准备工作:添加 JWT 依赖

pom.XML<dependencies> 标签中,新增 JWT 相关依赖(基于 JJWT 框架,Spring 官方推荐):

        <!-- JWT 核心依赖(JJWT) -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <!-- JWT 实现依赖 -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <!-- JWT 加密算法依赖 -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

添加后点击 IDEA 右上角的 “Load Maven Changes” 刷新依赖,确保无红色报错。

三、第一步:实现 JWT 工具类(核心)

JWT 的核心操作包括 生成 Token验证 Token解析 Token 中的用户信息,我们创建一个工具类封装这些逻辑,方便后续调用。

com.example.firstspringbootproject.utils 包下创建 JwtUtil 类:

package com.example.firstspringbootproject.utils;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import Java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtUtil {
    // 1. 从配置文件读取 JWT 关键参数(避免硬编码)
    @Value("${jwt.secret}") // 密钥(必须保密,建议在生产环境用环境变量配置)
    private String secret;
    @Value("${jwt.expiration}") // Token 过期时间(单位:毫秒,这里配置 2 小时)
    private long expiration;
    @Value("${jwt.header}") // 请求头中携带 Token 的字段名(如 Authorization)
    private String tokenHeader;
    @Value("${jwt.prefix}") // Token 前缀(如 Bearer,规范要求加空格)
    private String tokenPrefix;
    // 2. 生成 Token:基于用户信息(用户名、角色)
    public String generateToken(UserDetails userDetails) {
        // 存储 Token 中的自定义信息(Payload)
        Map<String, Object> claims = new HashMap<>();
        // 将用户角色存入 Token(后续验证权限用)
        claims.put("roles", userDetails.getAuthorities().stream()
                .map(authority -> authority.getAuthority())
                .toList());
        // 构建 Token 并返回
        return Jwts.builder()
                .setClaims(claims) // 自定义信息
                .setSubject(userDetails.getUsername()) // 用户名(唯一标识)
                .setIssuedAt(new Date()) // 签发时间
                .setExpiration(new Date(System.currentTimeMillis() + expiration)) // 过期时间
                .signWith(SignatureAlgorithm.HS512, secret) // 加密算法(HS512)+ 密钥
                .compact();
    }
    // 3. 从 Token 中获取用户名
    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }
    // 4. 验证 Token 是否有效(未过期 + 用户名匹配)
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUsernameFromToken(token);
        // 验证逻辑:用户名一致 + Token 未过期 + Token 未被篡改
        return username.equals(userDetails.getUsername())
                && !isTokenExpired(token);
    }
    // 5. 从 Token 中获取自定义角色信息
    public String getRoleFromToken(String token) {
        Claims claims = getAllClaimsFromToken(token);
        // 从自定义信息中获取角色列表(这里简化为单个角色,多角色可返回 List)
        return ((List<String>) claims.get("roles")).get(0);
    }
    // ------------------------------
    // 以下是内部工具方法(无需外部调用)
    // ------------------------------
    // 解析 Token,获取所有自定义信息(Payload)
    private Claims getAllClaimsFromToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret) // 用密钥解密
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException | MalformedJwtException | SignatureException
                 | IllegalArgumentException | UnsupportedJwtException e) {
            // 捕获 Token 异常(过期、格式错误、签名错误等)
            throw new RuntimeException("无效的 Token:" + e.getMessage());
        }
    }
    // 从 Token 中获取指定信息(通用方法)
    private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }
    // 判断 Token 是否过期
    private boolean isTokenExpired(String token) {
        final Date expirationDate = getClaimFromToken(token, Claims::getExpiration);
        return expirationDate.before(new Date());
    }
    // 6. 辅助方法:从请求头中提取 Token(去除前缀)
    public String extractTokenFromHeader(String header) {
        if (header != null && header.startsWith(tokenPrefix)) {
            // 例如:header = "Bearer eyJhbGciOiJIUzI1NiJ9...",返回后面的 Token 部分
            return header.substring(tokenPrefix.length()).trim();
        }
        return null;
    }
    // Getter 方法(供外部获取配置参数)
    public String getTokenHeader() {
        return tokenHeader;
    }
    public String getTokenPrefix() {
        return tokenPrefix;
    }
}

四、第二步:配置 JWT 参数(避免硬编码)

src/main/resources/application.yml(或 application.properties)中,添加 JWT 相关配置(替换硬编码,方便后续修改):

# JWT 配置
jwt:
  secret: firstspringbootproject2025secretkeyfirstspringbootproject2025secretkeyfirstspringbootproject2025secretkey # 密钥(生产环境建议用 64 位以上随机字符串)
#  expiration: 7200000 # Token 过期时间(7200000 毫秒 = 2 小时)
  expiration: 1000 # Token 过期时间(1000 毫秒 = 1 秒)
  header: Authorization # 请求头字段名
  prefix: Bearer  # Token 前缀(注意末尾有空格)

五、第三步:实现 JWT 登录接口(替换 HTTP Basic)

HTTP Basic 登录是通过浏览器弹窗输入账号密码,体验较差;我们需要自定义一个 登录接口(如 /api/login),客户端通过 JSON 提交账号密码,服务器验证通过后返回 JWT Token。

1. 创建登录请求参数实体类

com.example.firstspringbootproject.dto 包下创建 LoginRequestDTO(接收客户端提交的账号密码):

package com.example.firstspringbootproject.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(name = "LoginRequestDTO", description = "登录请求参数")
public class LoginRequestDTO {
    @NotBlank(message = "用户名不能为空")
    @Schema(description = "用户名", example = "admin")
    private String username;
    @NotBlank(message = "密码不能为空")
    @Schema(description = "密码", example = "123456")
    private String password;
}

2. 创建登录控制器

com.example.firstspringbootproject.controller 包下创建 AuthController,实现登录接口:

package com.example.firstspringbootproject.controller;
import com.example.firstspringbootproject.dto.LoginRequestDTO;
import com.example.firstspringbootproject.common.Result;
import com.example.firstspringbootproject.utils.JwtUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
@Tag(name = "认证接口", description = "登录、Token 相关接口")
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager; // Spring Security 认证管理器
    @Autowired
    private JwtUtil jwtUtil; // 自定义 JWT 工具类
    /**
     * 登录接口:接收账号密码,验证通过后返回 JWT Token
     */
    @PostMapping("/login")
    @Operation(summary = "用户登录", description = "提交用户名和密码,获取 JWT Token")
    public Result<Map<String, String>> login(@Valid @RequestBody LoginRequestDTO loginRequest) {
        // 1. 调用 Spring Security 认证管理器,验证账号密码
        Authentication authentication = authenticationManager.authenticate(
                new UsernamewNNesFEATFPasswordAuthenticationToken(
                        loginRequest.getUsername(),
                        loginRequest.getPassword()
                )
        );
        // 2. 认证通过:从认证结果中获取用户信息
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        // 3. 生成 JWT Token
        String token = jwtUtil.generateToken(userDetails);
        // 4. 构建返回结果(包含 Token 和过期提示)
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("token", token);
        resultMap.put("expiration", "Token 有效期 2 小时,请及时刷新");
        resultMap.put("role", jwtUtil.getRoleFromToken(token)); // 返回用户角色,方便前端处理
        return Result.success(resultMap);
    }
}

六、第四步:实现 JWT 认证过滤器(核心拦截逻辑)

客户端登录成功后,后续请求会在 Authorization 头中携带 Token(格式:Bearer eyJhbGciOiJIUzI1NiJ9...)。我们需要自定义一个 过滤器,在请求到达接口前拦截 Token,完成以下操作:

  • 从请求头中提取 Token;
  • 验证 Token 有效性;
  • 从 Token 中解析用户信息和角色;
  • 将用户信息存入 Spring Security 上下文,让后续权限校验生效。

com.example.firstspringbootproject.filter 包下创建 JwtAuthenticationFilter 类:

package com.example.firstspringbootproject.filter;
import com.example.firstspringbootproject.utils.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
// 自定义 JWT 认证过滤器:每次请求都会执行(OncePerRequestFilter 确保一次请求只执行一次)
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private UserDetailsService userDetailsService; // 之前实现的用户查询服务
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain
    ) throws ServletException, IOException {
        try {
            // 1. 从请求头中提取 Token
            String token = jwtUtil.extractTokenFromHeader(
                    request.getHeader(jwtUtil.getTokenHeader())
            );
            // 2. 验证 Token:非空 + 有效
            if (token != null) {
                // 2.1 从 Token 中获取用户名
                String username = jwtUtil.getUsernameFromToken(token);
                // 2.2 若用户名存在,且 Spring Security 上下文未存储用户信息(未登录)
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    // 2.3 从数据库查询用户完整信息(UserDetails)
                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                    // 2.4 验证 Token 有效性(未过期 + 用户名匹配)
                    if (jwtUtil.validateToken(China编程token, userDetails)) {
                        // 3. 构建认证对象,存入 Spring Security 上下文
                        UsernamePasswordAuthenticationToken authentication =
                                new UsernamePasswordAuthenticationToken(
                                        userDetails, // 用户信息
                                        null, // 密码(已验证,无需存储)
                                        userDetails.getAuthorities() // 用户权限(角色)
                                );
                        // 设置请求详情(如 IP、会话 ID)
                        authentication.setDetails(
                                new WebAuthenticationDetailsSource().buildDetails(request)
                        );
                        // 将认证对象存入上下文:后续接口权限校验会从这里获取用户信息
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
            }
        } catch (Exception e) {
            // Token 验证失败(如过期、篡改),打印日志但不阻断请求(后续会返回 401)
            logger.error("JWT Token 验证失败:" + e.getMessage());
        }
        // 4. 继续执行过滤器链(让请求到达后续接口或过滤器)
        filterChain.doFilter(request, response);
    }
}

七、第五步:重构 SecurityConfig(适配 JWT)

之前的 SecurityConfig 基于 HTTP Basic 登录,现在需要修改为 JWT 无状态登录,核心调整点:

  • 关闭 Session(无状态登录不需要 Session);
  • 放行登录接口(/api/login);
  • 将 JWT 过滤器加入过滤器链;
  • 移除 HTTP Basic 配置,保留统一异常处理。

修改 com.example.firstspringbootproject.config.SecurityConfig 类:

package com.example.firstspringbootproject.config;
import com.example.firstspringbootproject.common.Result;
import com.example.firstspringbootproject.entity.SysUser;
import com.example.firstspringbootproject.filter.JwtAuthenticationFilter;
import com.example.firstspringbootproject.mapper.SysUserMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFounphpdException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // 启用方法级权限控制(如 @PreAuthorize("hasRole('ADMIN')"))
public class SecurityConfig {
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter; // 自定义 JWT 过滤器
    // 1. 密码编码器(不变)
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    // 2. 用户详情服务(不变)
    @Bean
    public UserDetailsService userDetailsService() {
        return username -> {
            SysUser sysUser = sysUserMapper.findByUsername(username);
            if (sysUser == null) {
                throw new UsernameNotFoundException("用户不存在: " + username);
            }
            return sysUser;
        };
    }
    // 3. 认证提供者(不变)
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }
    // 4. 认证管理器(不变)
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
    // 5. 核心规则配置(重点修改:适配 JWT)
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 1. 关闭 CSRF(前后端分离必须关)
                .csrf(csrf -> csrf.disable())
                // 2. 关闭 Session(无状态登录核心:不创建和使用 Session)
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreatijsonPolicy.STATELESS)
                )
                // 3. 配置接口访问规则(调整放行接口)
                .authorizeHttpRequests(auth -> auth
                        // ① 放行:接口文档(Knife4j)、登录接口
                        .requestMatchers("/doc.html", "/webjars/**", "/v3/api-docs/**", "/api/login").permitAll()
                        // ② 管理员接口:仅 ADMIN 可访问
                        .requestMatchers("/api/user/all").hasRole("ADMIN")
                        // ③ 普通用户接口:USER/ADMIN 可访问
                        .requestMatchers("/api/user/**", "/api/product/**").hasAnyRole("USER", "ADMIN")
                        // ④ 其他接口:必须登录(Token 有效)
                        .anyRequest().authenticated()
                )
                // 4. 加入 JWT 过滤器:在 UsernamePasswordAuthenticationFilter 之前执行
                // (先验证 Token,再执行后续认证逻辑)
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                // 5. 统一异常处理(不变:未登录返回 401,权限不足返回 403)
                .exceptionHandling(ex -> ex
                        .authenticationEntryPoint((request, response, authException) -> {
                            response.setContentType("application/json;charset=UTF-8");
                            Result<Void> result = Result.error(401, "未登录或 Token 已过期,请重新登录");
                            response.getWriter().write(objectMapper.writeValueAsString(result));
                        })
                        .AccessDeniedHandler((request, response, accessDeniedException) -> {
                            response.setContentType("application/json;charset=UTF-8");
                            Result<Void> result = Result.error(403, "权限不足,无法访问");
                            response.getWriter().write(objectMapper.writeValueAsString(result));
                        })
                );
        // 关联认证提供者
        http.authenticationProvider(authenticationProvider());
        return http.build();
    }
}

八、第六步:测试 JWT 无状态登录流程

启动项目,用 Apifox 测试完整流程,验证无状态登录和权限控制是否生效:

1. 测试 1:调用登录接口,获取http://www.chinasem.cn Token

  • 请求地址http://localhost:8080/api/login
  • 请求方法:POST
  • 请求体(JSON)
{
    "username": "admin",
    "password": "123456"
}
  • 响应结果(成功)
{
    "code": 200,
    "msg": "success",
    "data": {
        "role": "ROLE_ADMIN",
        "expiration": "Token 有效期 2 小时,请及时刷新",
        "token": "eyJhbGciOiJIUzUxMiJ9.eyJyb2xlcyI6WyJST0xFX0FETUlOIl0sInN1YiI6ImFkbWluIiwiaWF0IjoxNzYzNDgxMDk0LCJleHAiOjE3NjM0ODgyOTR9.hSxBCTlQo5tUai-knfM2Sh4nVmehizOslcHkvG86jdC-U7-EztskPkF0r4G0DcaTMV3eFcJUu4pCewDdnniq2A"
    }
}

复制返回的 token,后续请求会用到。

2. 测试 2:携带 Token 访问管理员接口

  • 请求地址http://localhost:8080/api/user/all(需 ADMIN 角色)
  • 请求方法:GET
  • 请求头:添加 Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJyb2xlcyI6WyJST0xFX0FETUlOIl0sInN1YiI6ImFkbWluIiwiaWF0IjoxNzYzNDgxMDk0LCJleHAiOjE3NjM0ODgyOTR9.hSxBCTlQo5tUai-knfM2Sh4nVmehizOslcHkvG86jdC-U7-EztskPkF0r4G0DcaTMV3eFcJUu4pCewDdnniq2A(注意 Bearer 后有空格)
  • 响应结果(成功)
{
    "code": 200,
    "msg": "success",
    "data": [
        {
            "id": 1,
            "name": "小明",
            "age": 20,
            "phone": "13800138000"
        },
        {
            "id": 2,
            "name": "小红",
            "age": 19,
            "phone": "13900139000"
        },
        {
            "id": 3,
            "name": "小李",
            "age": 22,
            "phone": "13700137000"
        }
    ]
}

3. 测试 3:普通用户 Token 访问管理员接口(权限不足)

  • 先用 zhangsan(密码 123456)调用登录接口,获取普通用户 Token;
  • 携带普通用户 Token 访问 http://localhost:8080/api/user/all
  • 响应结果(失败)
{
    "code": 403,
    "msg": "权限不足,无法访问",
    "data": null
}

4. 测试 4:Token 过期(模拟)

  • 修改 application.ymljwt.expiration1000(1 秒过期);
  • 重新登录获取 Token,1 秒后携带 Token 访问接口;
  • 响应结果(失败)
{
    "code": 401,
    "msg": "未登录或 Token 已过期,请重新登录",
    "data": null
}

九、常见问题与优化建议

1. 问题:Token 被盗用怎么办?

  • 原因:JWT Token 一旦生成,在过期前无法主动作废;
  • 解决方案
  1. 缩短 Token 过期时间(如 30 分钟),同时实现 Token 刷新接口(用旧 Token 换取新 Token,避免频繁登录);
  2. 维护一个 黑名单(如 Redis),用户登出或 Token 被盗时,将 Token 加入黑名单,验证时先检查是否在黑名单中。

2. 问题:密钥(secret)泄露怎么办?

  • 原因:密钥是 JWT 安全的核心,泄露后攻击者可伪造 Token;
  • 解决方案
  1. 生产环境中,密钥通过 环境变量配置中心 注入,不写入代码或配置文件;
  2. 使用 非对称加密算法(如 RS256),用私钥生成 Token,公钥验证 Token,私钥严格保密。

## 十、总结:JWT 无状态登录的核心价值

通过本文的改造,我们实现了 Spring Boot + Spring Security + JWT 的无状态登录,核心优势总结如下:

  • 分布式友好:服务器无需存储 Session,多台服务器可直接共用 Token 验证逻辑;
  • 前后端分离适配:通过请求头携带 Token,无需依赖 Cookie,适配移动端、小程序等多端场景;
  • 安全性提升:Token 包含过期时间和加密签名,避免身份信息被篡改;
  • 扩展性强:Token 可自定义存储用户角色、权限等信息,减少数据库查询次数。

至此,恭喜你已具备初级程序员开发水平,可以试着投简历找工作啦。

到此这篇关于Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南的文章就介绍到这了,更多相关Spring Boot JWT Spring Security 无状态登录内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156294

相关文章

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位