Spring Boot 接口权限控制:登录 + JWT 实战

Springboot3: JWT认证支持 JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。由三部分组成:1,头部(header): token类型和签名算法, json2,数据(payload): 存放实际需要传递的数据,json3,签名(Signature):base64编码过的header数据+"."+base64编码过的payload数据,服务端密钥,从头部获取签名算法,进行加密获得。 阅读详情

Spring Boot 接口权限控制:登录 + JWT 实战

在Spring Boot项目开发中,完成接口开发只是基础,接口的安全控制才是提升项目专业度的关键——如果接口没有权限校验,任何人都能随意调用接口、操作数据,会造成严重的安全隐患。本文承接“接口开发完成后无安全控制”的场景,手把手教大家实现用户登录接口、整合JWT完成令牌生成与验证,以及通过拦截器/过滤器实现接口权限校验,完整落地接口安全体系,适配实际项目与毕设需求,快速提升开发专业度。

一、前置准备:环境搭建与核心依赖

本次实战基于Spring Boot + MyBatis-Plus + JWT + Spring Security(简化版),核心依赖如下,无需额外引入过多复杂组件,兼顾轻量与实用。

1.1 Maven 核心依赖

<!-- Spring Boot Web 核心依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- MyBatis-Plus 核心依赖(操作数据库) -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- JWT 核心依赖(生成/验证令牌) -->
<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>

<!-- lombok 简化实体类 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

<!-- Spring Security 简化版(可选,用于权限注解) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

1.2 核心配置(application.yml)

配置数据库连接、JWT核心参数(密钥、过期时间)、MyBatis-Plus相关配置,集中管理,便于后续修改:

spring:
  # 数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot_jwt?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    username: root
    password: 123456
  # Spring Security 配置(关闭默认登录页,简化配置)
  security:
    basic:
      enabled: false
    user:
      name: admin
      password: admin

# MyBatis-Plus 配置
mybatis-plus:
  mapper-locations: classpath:mybatis/mapper/**/*.xml
  type-aliases-package: com.example.demo.entity
  configuration:
    map-underscore-to-camel-case: true # 驼峰命名映射
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志(便于调试)

# JWT 自定义配置(自己定义,后续代码中读取)
jwt:
  secret: springboot-jwt-2026-security-key # 密钥(生产环境需更换为复杂密钥,避免泄露)
  expiration: 86400000 # 令牌过期时间(单位:毫秒),这里设置为24小时
  header: Authorization # 请求头中携带令牌的字段名,默认Authorization

1.3 数据库表设计(用户表)

核心是用户表,存储用户名、密码(加密存储)、角色(用于后续权限区分,简化版用字符串表示),无需复杂设计,适配登录与权限校验核心需求:

CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户主键',
  `username` varchar(50) NOT NULL COMMENT '用户名(唯一)',
  `password` varchar(100) NOT NULL COMMENT '密码(加密存储)',
  `role` varchar(20) NOT NULL COMMENT '用户角色(如:admin、user)',
  `status` tinyint(1) DEFAULT 1 COMMENT '状态(1:正常,0:禁用)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';

说明:密码需加密存储(本文使用BCrypt加密,Spring Security自带,无需额外引入工具),禁止明文存储,避免安全风险。

二、核心实战一:用户登录接口设计

登录接口是权限控制的入口,核心逻辑:接收前端传入的用户名/密码 → 校验用户名是否存在、密码是否匹配 → 校验通过生成JWT令牌 → 返回令牌给前端;校验失败返回错误信息。

2.1 实体类与DTO设计

2.1.1 用户实体类(SysUser)
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;

/**
 * 系统用户实体类
 */
@Data
@TableName("sys_user")
public class SysUser {
    @TableId(type = IdType.AUTO)
    private Long id;

    // 用户名(唯一)
    private String username;

    // 加密后的密码
    private String password;

    // 用户角色(admin:管理员,user:普通用户)
    private String role;

    // 状态(1:正常,0:禁用)
    private Integer status;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
}
2.1.2 登录请求DTO(LoginDTO)

接收前端传入的登录参数,用于参数校验(用户名、密码非空):

import lombok.Data;
import javax.validation.constraints.NotBlank;

/**
 * 登录请求DTO(接收前端参数)
 */
@Data
public class LoginDTO {
    // 用户名,非空校验
    @NotBlank(message = "用户名不能为空")
    private String username;

    // 密码,非空校验
    @NotBlank(message = "密码不能为空")
    private String password;
}
2.1.3 登录响应DTO(LoginVO)

返回给前端的结果,包含JWT令牌、用户名、角色等信息,避免返回敏感数据(如加密后的密码):

import lombok.Data;

/**
 * 登录响应VO(返回给前端)
 */
@Data
public class LoginVO {
    // JWT令牌
    private String token;

    // 用户名
    private String username;

    // 用户角色
    private String role;

    // 令牌过期时间(单位:毫秒)
    private Long expiration;
}

2.2 Mapper、Service层实现(用户校验)

2.2.1 SysUserMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * 用户Mapper接口
 */
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
    // 根据用户名查询用户(登录核心查询)
    SysUser selectByUsername(@Param("username") String username);
}
2.2.2 SysUserService

核心是用户校验逻辑:查询用户、校验密码、校验用户状态,使用Spring Security的BCryptPasswordEncoder进行密码加密与匹配:

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.SysUser;
import com.example.demo.mapper.SysUserMapper;
import com.example.demo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * 用户Service层
 */
@Service
public class SysUserService extends ServiceImpl<SysUserMapper, SysUser> {

    @Autowired
    private SysUserMapper sysUserMapper;

    // BCrypt密码加密器(Spring Security自带)
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    /**
     * 登录校验:根据用户名和密码校验用户
     * @param username 用户名
     * @param password 明文密码
     * @return 校验通过的用户信息
     */
    public SysUser loginCheck(String username, String password) {
        // 1. 根据用户名查询用户
        SysUser user = sysUserMapper.selectByUsername(username);
        Assert.notNull(user, "用户名不存在");

        // 2. 校验用户状态(是否禁用)
        Assert.isTrue(user.getStatus() == 1, "用户已禁用,请联系管理员");

        // 3. 校验密码(明文密码与数据库加密密码匹配)
        Assert.isTrue(passwordEncoder.matches(password, user.getPassword()), "密码错误");

        // 4. 校验通过,返回用户信息(注意:不要返回密码)
        user.setPassword(null);
        return user;
    }

    /**
     * 新增用户(用于测试,密码自动加密)
     * @param user 用户信息
     * @return 新增结果
     */
    public boolean addUser(SysUser user) {
        // 密码加密后存储
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return save(user);
    }
}

2.3 Controller层:登录接口实现

接收前端请求,调用Service层校验用户,校验通过后调用JWT工具类生成令牌,返回登录结果:

import com.example.demo.dto.LoginDTO;
import com.example.demo.dto.LoginVO;
import com.example.demo.entity.SysUser;
import com.example.demo.service.SysUserService;
import com.example.demo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
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 javax.validation.Valid;

/**
 * 登录控制器
 */
@RestController
@RequestMapping("/auth")
@Validated
public class LoginController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private JwtUtil jwtUtil;

    // 从配置文件读取JWT过期时间
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 用户登录接口
     * @param loginDTO 登录参数(用户名、密码)
     * @return 登录结果(JWT令牌等)
     */
    @PostMapping("/login")
    public LoginVO login(@Valid @RequestBody LoginDTO loginDTO) {
        // 1. 登录校验(用户名、密码、用户状态)
        SysUser user = sysUserService.loginCheck(loginDTO.getUsername(), loginDTO.getPassword());

        // 2. 生成JWT令牌(传入用户ID、用户名、角色)
        String token = jwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole());

        // 3. 组装返回结果
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setUsername(user.getUsername());
        loginVO.setRole(user.getRole());
        loginVO.setExpiration(expiration);

        return loginVO;
    }
}

2.4 测试登录接口

  1. 先调用addUser方法新增测试用户(如username=admin,password=123456,role=admin),密码会自动加密存储;

    2. 用Postman调用POST接口:http://localhost:8080/auth/login,请求体如下:
    
{
  "username": "admin",
  "password": "123456"
}
  1. 响应结果(成功):返回token、username、role、expiration,前端需存储token,后续请求接口时携带该token。

三、核心实战二:JWT 生成与验证(工具类实现)

JWT(JSON Web Token)是一种无状态的令牌机制,核心优势是无需在服务器存储会话信息,仅通过令牌本身即可完成身份验证,适合分布式系统。本文封装JWT工具类,实现令牌生成、验证、解析核心功能。

3.1 JWT工具类(JwtUtil)

核心逻辑:读取配置文件中的密钥和过期时间,使用jjwt依赖提供的API生成令牌、验证令牌有效性、解析令牌中的用户信息(用户ID、用户名、角色)。

import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;

/**
 * JWT工具类:生成令牌、验证令牌、解析令牌
 */
@Component
public class JwtUtil {

    // 从配置文件读取JWT密钥
    @Value("${jwt.secret}")
    private String secret;

    // 从配置文件读取令牌过期时间(毫秒)
    @Value("${jwt.expiration}")
    private Long expiration;

    // 令牌前缀(规范写法,前端请求头携带时需加上)
    private static final String TOKEN_PREFIX = "Bearer ";

    /**
     * 生成JWT令牌
     * @param userId 用户ID
     * @param username 用户名
     * @param role 用户角色
     * @return JWT令牌(不带前缀)
     */
    public String generateToken(Long userId, String username, String role) {
        // 令牌过期时间 = 当前时间 + 配置的过期时间
        Date expirationDate = new Date(System.currentTimeMillis() + expiration);

        // 构建JWT令牌
        return Jwts.builder()
                // 载荷:存储用户核心信息(自定义字段)
                .claim("userId", userId)
                .claim("username", username)
                .claim("role", role)
                // 主题(可自定义,一般存储用户名)
                .setSubject(username)
                // 签发时间
                .setIssuedAt(new Date())
                // 过期时间
                .setExpiration(expirationDate)
                // 签名算法:HS256,使用配置的密钥
                .signWith(SignatureAlgorithm.HS256, secret)
                // 压缩令牌
                .compact();
    }

    /**
     * 验证JWT令牌有效性
     * @param token 待验证的令牌(可带前缀,也可不带)
     * @return true:有效,false:无效
     */
    public boolean validateToken(String token) {
        try {
            // 去除令牌前缀(如果有)
            token = token.replace(TOKEN_PREFIX, "");
            // 解析令牌,验证签名和过期时间
            Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            // 捕获所有异常(签名错误、令牌过期、格式错误等)
            return false;
        }
    }

    /**
     * 解析JWT令牌,获取载荷中的用户信息(通用方法)
     * @param token 令牌(可带前缀)
     * @return 载荷对象(包含自定义的userId、username、role)
     */
    public Claims parseToken(String token) {
        token = token.replace(TOKEN_PREFIX, "");
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 从令牌中获取用户名
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.get("username", String.class);
    }

    /**
     * 从令牌中获取用户角色
     * @param token 令牌
     * @return 用户角色
     */
    public String getRoleFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.get("role", String.class);
    }

    /**
     * 从令牌中获取用户ID
     * @param token 令牌
     * @return 用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.get("userId", Long.class);
    }
}

3.2 JWT核心注意事项

1. 密钥(secret):生产环境必须更换为复杂的随机字符串(如32位随机字符),避免泄露,否则会导致令牌被伪造;

2. 过期时间(expiration):根据业务需求设置,一般为1-24小时,过期后前端需重新登录获取新令牌;

3. 载荷信息:仅存储非敏感核心信息(如用户ID、用户名、角色),禁止存储密码、手机号等敏感数据;

4. 令牌前缀:前端请求时,需在请求头Authorization中携带令牌,格式为:Bearer + 空格 + 令牌(如:Bearer eyJhbGciOiJIUzI1NiJ9...)。

四、核心实战三:拦截器 / 过滤器实现接口权限校验

生成JWT令牌后,需要拦截所有需要权限的接口,校验令牌的有效性、用户的权限,实现接口保护。本文分别实现两种方式:拦截器(HandlerInterceptor)和过滤器(Filter),按需选择,核心逻辑一致。

方式一:拦截器(HandlerInterceptor)实现权限校验

拦截器是Spring MVC提供的组件,可拦截请求的预处理、后处理,适合与Spring生态整合,便于获取Spring容器中的Bean(如JwtUtil),推荐使用。

4.1.1 自定义拦截器(JwtInterceptor)

核心逻辑:拦截请求 → 从请求头获取令牌 → 验证令牌有效性 → 解析用户信息 → 校验用户权限(可选) → 放行;若令牌无效/无令牌,直接返回401未授权。

import com.example.demo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * JWT拦截器:实现接口权限校验
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    // 从配置文件读取请求头中令牌的字段名
    @Value("${jwt.header}")
    private String jwtHeader;

    /**
     * 请求预处理(核心方法):在接口执行前拦截,校验令牌
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 从请求头中获取令牌
        String token = request.getHeader(jwtHeader);

        // 2. 校验令牌是否存在
        if (token == null || token.trim().isEmpty()) {
            responseError(response, "未携带令牌,请先登录");
            return false;
        }

        // 3. 验证令牌有效性
        if (!jwtUtil.validateToken(token)) {
            responseError(response, "令牌无效或已过期,请重新登录");
            return false;
        }

        // 4. (可选)权限校验:根据业务需求,校验用户角色是否有权限访问当前接口
        // 示例:假设/admin/**接口只有admin角色可访问
        String requestUri = request.getRequestURI();
        String role = jwtUtil.getRoleFromToken(token);
        if (requestUri.startsWith("/admin/") && !"admin".equals(role)) {
            responseError(response, "权限不足,无法访问");
            return false;
        }

        // 5. 令牌校验通过,放行请求
        return true;
    }

    /**
     * 响应错误信息(统一返回JSON格式)
     */
    private void responseError(HttpServletResponse response, String message) throws Exception {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401未授权
        PrintWriter out = response.getWriter();
        out.write("{\"code\":401,\"message\":\"" + message + "\"}");
        out.flush();
        out.close();
    }
}
4.1.2 注册拦截器(配置拦截规则)

通过WebMvcConfigurer配置拦截器,指定拦截哪些接口、放行哪些接口(如登录接口无需拦截):

import com.example.demo.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Spring MVC 配置:注册JWT拦截器
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private JwtInterceptor jwtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                // 拦截所有接口
                .addPathPatterns("/**")
                // 放行接口(无需权限校验)
                .excludePathPatterns(
                        "/auth/login", // 登录接口
                        "/auth/register", // 注册接口(如果有)
                        "/swagger-ui/**", // Swagger文档(开发环境放行)
                        "/v3/api-docs/**" // Swagger接口(开发环境放行)
                );
    }
}

方式二:过滤器(Filter)实现权限校验

过滤器是Servlet提供的组件,作用于请求进入Servlet之前,更底层,适合通用的权限校验场景。实现逻辑与拦截器一致,仅代码写法不同。

4.2.1 自定义过滤器(JwtFilter)
import com.example.demo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * JWT过滤器:实现接口权限校验
 */
@Component
public class JwtFilter implements Filter {

    @Autowired
    private JwtUtil jwtUtil;

    @Value("${jwt.header}")
    private String jwtHeader;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 1. 获取令牌
        String token = request.getHeader(jwtHeader);

        // 2. 校验令牌是否存在
        if (token == null || token.trim().isEmpty()) {
            responseError(response, "未携带令牌,请先登录");
            return;
        }

        // 3. 验证令牌有效性
        if (!jwtUtil.validateToken(token)) {
            responseError(response, "令牌无效或已过期,请重新登录");
            return;
        }

        // 4. (可选)权限校验(与拦截器逻辑一致)
        String requestUri = request.getRequestURI();
        String role = jwtUtil.getRoleFromToken(token);
        if (requestUri.startsWith("/admin/") && !"admin".equals(role)) {
            responseError(response, "权限不足,无法访问");
            return;
        }

        // 5. 放行请求
        filterChain.doFilter(request, response);
    }

    // 响应错误信息(与拦截器一致)
    private void responseError(HttpServletResponse response, String message) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter out = response.getWriter();
        out.write("{\"code\":401,\"message\":\"" + message + "\"}");
        out.flush();
        out.close();
    }
}
4.2.2 注册过滤器

通过FilterRegistrationBean注册过滤器,指定拦截规则,与拦截器的放行/拦截逻辑一致:

import com.example.demo.filter.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 过滤器配置:注册JWT过滤器
 */
@Configuration
public class FilterConfig {

    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    public FilterRegistrationBean<JwtFilter> jwtFilterRegistration() {
        FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(jwtFilter);
        // 拦截所有接口
        registrationBean.addUrlPatterns("/*");
        // 放行接口(与拦截器一致)
        registrationBean.addInitParameter("excludedPaths", "/auth/login,/auth/register,/swagger-ui/**,/v3/api-docs/**");
        registrationBean.setName("JwtFilter");
        registrationBean.setOrder(1); // 过滤器执行顺序,越小越先执行
        return registrationBean;
    }
}

拦截器与过滤器对比(选型建议)

对比维度拦截器(HandlerInterceptor)过滤器(Filter)
所属框架Spring MVCServlet
执行时机请求进入Controller之前请求进入Servlet之前(更底层)
依赖Spring是,可直接注入Spring Bean(如JwtUtil)否,需通过配置注入Bean,稍繁琐
适用场景Spring Boot项目,需要结合Spring生态(如权限注解)通用Java Web项目,无需依赖Spring
选型建议:Spring Boot项目优先使用拦截器,整合更顺畅,代码更简洁;非Spring项目使用过滤器。

五、实战测试:接口权限校验效果

5.1 测试场景1:未携带令牌访问需要权限的接口

调用接口:http://localhost:8080/admin/user/list(假设是管理员接口),未在请求头携带Authorization令牌,响应结果:

{
  "code": 401,
  "message": "未携带令牌,请先登录"
}

5.2 测试场景2:携带无效令牌访问接口

请求头携带错误令牌(如随意输入字符串),响应结果:

{
  "code": 401,
  "message": "令牌无效或已过期,请重新登录"
}

5.3 测试场景3:普通用户访问管理员接口

使用role=user的用户登录,获取令牌,携带令牌访问/admin/user/list接口,响应结果:

{
  "code": 401,
  "message": "权限不足,无法访问"
}

5.4 测试场景4:携带有效令牌访问接口

使用role=admin的用户登录,获取令牌,在请求头添加:Authorization: Bearer 令牌,访问/admin/user/list接口,正常返回接口数据,校验通过。

六、常见问题与解决方案

  1. 令牌验证失败,提示“签名错误”?

    解决方案:① 检查JwtUtil中使用的密钥(secret)是否与配置文件一致;② 确认前端携带的令牌是否完整,无多余空格或字符;③ 检查令牌生成时的签名算法(本文用HS256)与验证时是否一致。
    
  2. 拦截器/过滤器未生效?

    解决方案:① 检查拦截器/过滤器是否添加@Component注解(注入Spring容器);② 检查注册配置类(WebMvcConfig/FilterConfig)是否添加@Configuration注解;③ 确认拦截规则是否正确,避免放行接口写错。
    
  3. 前端携带令牌后,后端仍提示“未携带令牌”?

    解决方案:① 检查前端请求头字段名是否与配置文件中jwt.header一致(默认Authorization);② 确认令牌格式是否正确(Bearer + 空格 + 令牌);③ 排查跨域问题(若前后端分离,需配置跨域允许携带请求头)。
    
  4. 密码加密后,登录时校验失败?

    解决方案:① 确认新增用户时,是否使用BCryptPasswordEncoder加密密码;② 登录校验时,是否使用matches方法(明文密码与加密密码匹配),而非直接equals比较。
    

七、总结

本文完整实现了Spring Boot接口权限控制的核心流程:从用户登录接口设计、JWT令牌生成与验证,到拦截器/过滤器实现权限校验,完美解决“接口无安全控制”的问题,提升项目专业度。核心要点:

  • 登录接口:核心是用户校验(用户名、密码、状态),密码必须加密存储,避免安全风险。

  • JWT工具类:封装生成、验证、解析令牌的核心方法,密钥和过期时间需配置化,便于维护。

  • 权限校验:优先使用拦截器(Spring Boot适配更好),按需配置拦截/放行规则,支持角色权限区分。

掌握本文内容后,可直接将代码整合到毕设或实际项目中,实现接口的安全保护。后续可进一步扩展:如令牌刷新机制、更细粒度的权限控制(基于接口的权限分配)、异常统一处理等,让权限体系更完善。

Spring boot+Spring security+JWT实现前后端分离登录认证及权限控制 基本上没讲什么底层实现,这篇是使用篇,后续会出SpringSecurity的底层源码讲解,并且如果本帖有问题的有疑问的读者可以在评论区留言,本人会积极处理。您的支持是我最大的动力,本人一直在努力的更新各种框架的使用和框架的源码解读~!先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。httpshttpshttps。... 阅读详情

相关推荐

Spring Boot 集成 JWT 实现用户认证和权限控制!

🏆本文收录于「滚雪球学SpringBoot」专栏,手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

**My Coding Family** 1236

【springboot开发】JWT实现用户验证登录

JWT完整流程如下:用户使用账号和密码发起 POST 请求;服务器使用私钥创建一个 JWT;服务器返回这个 JWT 给浏览器;浏览器将该 JWT 串在请求头中像服务器发送请求;服务器验证该 JWT;返回响应的资源给浏览器。

idiotyi的博客 2353

Spring Boot + SpringSecurity + JWT 实现简单的 restful Api 权限控制

对于前后端分离的项目,后端对于接口访问的权限控制是必须要做的,也就是需要根据用户的权限进行控制,这样才能对我们的接口资源进行一定程度的保护,在一个web项目中,我们的通常做法是,允许登录后的用户进行接口资源的访问,否则就需要进行拦截,比较成熟也比较流行的做法如下图所示, 我们大致梳理一下这个认证的流程如下, 1、用户访问后端某个接口,或者是需要操作web页面某个功能,如果没有认证,需要进行页面跳...

congge 1万+

spring boot 权限管理的几种方式

spring boot 权限

orton777的博客 6797

Spring Boot中JWT权限认证实践

JWT是一个开放标准(RFC 7519),它定义了一种简洁的、URL安全的编码方式,用于在各方之间以JSON对象的形式安全地传输信息。JWT由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。每个部分通过点()连接在一起,形成一个完整的JWT。JWT的优点在于:可扩展性:载荷可以携带用户身份及业务所需的任何数据。跨域适用性:基于标准格式,JWT被设计为易于跨域分享。性能高效。

weixin_36151775的博客 1177

ATGM332D模块串口配置保姆级教程:从9600波特率到NMEA数据过滤,一次搞定

本文提供ATGM332D模块串口配置的详细教程,涵盖从基础硬件连接到高级NMEA数据过滤的全过程。内容包括波特率优化、数据输出频率调整、NMEA语句过滤等实用技巧,帮助开发者快速掌握GNSS模块配置,提升定位系统性能。

weixin_30664051的博客 513

SpringBoot之JWT登录

是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息。3.前端接收到返回结果进行响应并将JWT保存,前端可以将返回的结果保存在localStorage(浏览器本地缓存)或sessionStorage(session缓存)上,退出登录时前端删除保存的JWT即可。4.后续前端每次请求携带JWT进行,后端检查JWT 的合法性存在验证JWT的有效性。5.验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。2.登录成功后,生成jwt令牌。

qq_62592925的博客 1427

第二十届全国大学生智能汽车竞赛极速光电组:MicroPython与恩智浦RT1021的硬件编程实战指南

本文为参加第二十届全国大学生智能汽车竞赛极速光电组的同学提供了一份详尽的MicroPython与恩智浦RT1021硬件编程实战指南。文章深入剖析了选择MicroPython与RT1021这对组合的优势,详细讲解了从开发环境搭建、基础硬件控制(如GPIO、PWM、编码器、CCD)到系统集成(平衡控制、循迹算法)与多任务调试的全过程,旨在帮助参赛者降低嵌入式开发门槛,高效备赛。

wdx0123456的博客 843

Spring Boot+Jwt+AOP+自定义注解实现接口的权限控制

之前在项目中通过自定义拦截器+自定义注解进行权限校验,拦截器代码过于臃肿!!!于是想到了使用面向切面的方法!!

心安.的博客 2522

RV1126 ISP开发实战:从Tuner调试到IQ文件解析

本文详细介绍了RV1126 ISP开发的完整流程,从Tuner调试到IQ文件解析,涵盖了环境搭建、工具使用、参数配置及性能优化等关键环节。通过实战案例和避坑指南,帮助开发者快速掌握Rockchip芯片的ISP开发技巧,提升图像处理质量。

weixin_29195615的博客 569

新入手的Atmel-ICE产品说明

【一句话自我介绍】 我是Atmel最新推出的功能强大的调试编程工具,适用于Atmel ARM® Cortex®-M的Atmel SAM和AVR® 系列芯片。 【我支持的软件】 完美支持Atmel Studio 6.2以上版本直接支持ICC8AVR以上版本支持烧录ICCAVR、CVAVR、IAR等生成的HEX文件 【我支持的器件】 支持AVR 32-bit MCUs的JTA

kaloha3的专栏 1万+

Spring Boot接口权限控制实战:JWT+拦截器从零搭建登录鉴权体系

接口权限控制是后端工程中绕不开的核心问题,本质上包含“认证”与“授权”两个环节。传统Session方案在分布式环境下存在同步难题,而JWT以无状态特性成为前后端分离架构的首选,Token本身携带用户身份信息,通过签名校验即可完成信任传递。在实际落地中,基于Spring Boot的自定义拦截器配合JWT工具类,既能实现登录认证、角色授权,又能灵活控制接口访问粒度,相比Spring Security更为轻量直观。该方案广泛应用于单点登录、分布式微服务、第三方登录打通等场景,同时还需关注Token续签、跨域携带、

weixin_29698641的博客 296

DAF-Net:动态注意力红外-可见光图像融合

DAF-Net 红外-可见光融合链路:IR/VIS 双分支 (Conv+ResBlock → 64ch) → DynamicAttentionFusion (Cat→Sigmoid→加权) → 重建 (Conv→Sigmoid)。TNO 上 SSIM=0.782 (vs IR), 0.734 (vs VIS), 参数量仅 218K。核心贡献:轻量动态注意力门控, 无监督 SSIM+MSE 损失不需要配准 ground truth。

FJN110的博客 318

Spring Boot + JWT + RBAC 权限系统实战,从登录鉴权到接口级权限控制完整落地

企业级权限系统设计实践 本文从企业后台系统开发痛点出发,系统介绍了基于Spring Boot + Spring Security + JWT + RBAC的权限系统实现方案。主要内容包括: 常见问题分析:指出角色权限混淆、前后端权限分离、粒度设计混乱等典型问题 核心目标:明确认证与授权的区别,强调接口级安全边界的重要性 RBAC模型优势:解析用户-角色-权限三层结构的解耦价值 权限点设计规范:提出"模块:资源:动作"的统一命名规则 JWT定位:说明JWT作为认证凭证而非权限系统的角色 实

百锦再的博客 2万+

Python 爬虫实战:共享单车数据采集全流程与市场洞察深度剖析

本文介绍了如何利用Python爬虫技术获取和分析共享单车运营数据。文章从项目背景出发,详细阐述了系统架构设计,包括数据抓取、清洗存储、分析和可视化模块。通过Scrapy、BeautifulSoup等工具实现数据采集,使用Pandas进行数据清洗,并借助Matplotlib进行可视化分析。实战部分展示了爬虫代码示例和城市分布、使用频率等分析案例。最终指出数据驱动分析有助于了解行业现状和市场趋势,未来可结合机器学习等方法进行深入洞察。该技术方案为共享单车行业研究提供了有效的数据支持。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2232

14、多层螺旋 CT 技术详解

本文详细解析了多层螺旋CT(MSCT)技术的原理与应用,涵盖其相对于单层螺旋CT的优势,包括图像采集速度提升、分辨率提高和噪声降低。文章深入探讨了扫描仪的几何结构、离散投影模型以及关键参数如切片宽度和螺距的影响,并重点介绍了z-滤波重建算法及其离散实现流程。通过流程图和公式推导,系统梳理了从投影获取到图像重建的全过程。同时分析了MSCT在临床中的实际应用案例及未来发展趋势,如更高分辨率、更低辐射剂量和智能化算法等方向,全面展示了MSCT在现代医学影像中的核心价值。

f0g1h2的博客 193

Spring Boot 2结合Spring security + JWT实现微信小程序登录

项目源码:https://gitee.com/tanwubo/jwt-spring-security-demo

qq_22606825的博客 1万+

Cadence PSpice 仿真0:绘制电路图方法图文教程

在使用PSpice进行电路的仿真时,首先需要使用带有PSpice模型的元器件来绘制电路图,本文简单介绍进行电路图绘制是常用的几种需要掌握的方法,以满足PSpice仿真绘制简单电路图所用。

fydar的博客 4702

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

分布式友好:服务器无需存储 Session,多台服务器可直接共用 Token 验证逻辑;前后端分离适配:通过请求头携带 Token,无需依赖 Cookie,适配移动端、小程序等多端场景;安全性提升:Token 包含过期时间和加密签名,避免身份信息被篡改;扩展性强:Token 可自定义存储用户角色、权限等信息,减少数据库查询次数。至此,恭喜你已具备初级程序员开发水平,可以试着投简历找工作啦。

weixin_42847133的博客 1280

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Spring Boot 3.x整合JWT全攻略:从登录拦截到接口权限控制的完整代码示例

本文详细介绍了如何在Spring Boot 3.x中整合JWT实现安全认证,涵盖从登录拦截到接口权限控制的完整流程。通过Spring Security和JWT的深度集成,开发者可以构建无状态、安全的RESTful API,并实现细粒度的权限管理。文章提供了完整的代码示例和最佳实践,帮助开发者快速掌握token验证机制。

dream的博客 813

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Spring Boot + JWT实现登录与接口权限控制:核心代码与避坑指南

在Java后端开发中,接口安全与登录认证是不可回避的基础工程。JWT作为一种无状态令牌方案,以签名校验替代服务端会话存储,天然适配分布式部署与前后端分离场景。其核心原理是将用户身份、角色与过期时间封装为令牌,服务端仅凭密钥验签即可完成认证;结合BCrypt密码加密、拦截器与注解授权,能够构建轻量而完整的权限控制链路。该方案广泛应用于RESTful API、微服务网关及多端登录系统,相比Spring Security更轻量、易掌控。本文从整体设计到代码落地,梳理Spring Boot集成JWT实现登录、鉴权、

weixin_31188927的博客 278

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

一次学会JWT:Java 登录、验证与权限控制全流程

JWT(JSON Web Token)是一种轻量级的无状态认证机制,通过JSON格式安全传输用户信息。它由Header(算法声明)、Payload(用户数据)和Signature(签名防篡改)三部分组成,采用Base64编码。相比传统Session,JWT具有跨平台、无服务器存储压力等优势。文章详细介绍了JWT工作原理,并通过SpringBoot项目演示了具体实现:使用jjwt库生成/验证Token,编写拦截器进行权限控制,配置登录接口和受保护API。最后给出了完整的API测试流程,展示了JWT在现代Web

2403_82614686的博客 1621

Spring Boot 如何保证接口安全

Spring Boot如何保证接口安全,需要架构设计、示例代码以及系统逻辑分析。首先,我得考虑常见的接口安全措施,比如身份认证、权限控制、数据加密、防止常见攻击等。然后,要结合Spring Boot的功能来实现这些措施。首先,身份认证,通常用Spring Security或者OAuth2。Spring Security比较基础,适合大部分场景。可能用JWT来做无状态认证,这样适合分布式系统。然后权限控制,可以用基于角色的访问控制(RBAC),或者更细粒度的权限管理。

g470641382的博客 1721
上一篇: Spring Boot 多表关联查询实战(一对多 _ 多对一)
下一篇: Spring Boot 文件上传与下载(图片 _ Excel)
码客日记
博客等级 码龄6年 149粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码客日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值