SpringSecurity+JWT简单集成的实现

 更新时间:2026年04月01日 08:58:38   作者:Zzxy  
本文主要介绍了SpringSecurity+JWT简单集成的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、认证与授权

  • 认证Authentication):验证用户身份
  • 授权Authorization):允许用户访问那些资源,验证用户权限

2、JWT无状态认证

JWT(JSON Web Token):无状态认证,是一种紧凑安全的开放标准,用于在网络应用环境间传递声明(claims)。

JWT = Header +Payload + Signature

  • Header:头部,包含令牌类型(通常是 "JWT")和签名算法(如 HMAC SHA256)。
  • Payload:有效载荷,包含用户信息和其他元数据(如过期时间等)。
  • Signature:签名部分,用于验证token的完整性。

服务端不保存Session,Token包含用户信息,客户端每次请求携带。

  • Token 通常指的是整个 JWT 字符串,它是由头部、负载和签名组成,经过编码并用点 (.) 分隔开
  • Http请求中:
(授权)Authorization: Bearer <token>

3、Spring Security + JWT 集成

3.1 添加依赖 pom.xml

<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</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>

3.2 JWT 相关配置

JWT 工具类:生成和解析Token

package com.example.utils;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtil {
    @Value("${jwt.secret:mySecretKey12345678901234567890123456789012}")
    private String secret;
    @Value("${jwt.expiration:86400000}")
    private Long expiration;  // 默认1天
    private Key getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes()); //生成 HMAC SHA 密钥
    }
    /**
     * 生成JWT Token
     */
    public String generateToken(Integer userId, String username) {
        Map<String, Object> claims = new HashMap<>();
        //claims映射,存储用户信息
        claims.put("userId", userId);
        claims.put("username", username);
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                .compact();
    }
    /**
     * 从Token中获取用户ID
     */
    public Integer getUserIdFromToken(String token) {
        //创建解析器,设置签名密钥,解析token,获取claims
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token) //解析Token
                .getBody();
        return claims.get("userId", Integer.class);
    }
    /**
     * 从Token中获取用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }
    /**
     验证Token是否有效
     * 验证给定的JWT是否有效,通过解析和验证 Token 的签名来实现这一点。
     */
    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}

3.3 Spring Security 相关配置

自定义UserDetailsService:实现基于数据库的用户认证与授权。

允许应用程序灵活地从任何数据源(如数据库)加载用户信息,并确保在用户登录时能够正确地验证身份及授权访问权限。

package com.example.security;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据用户名查询用户
        User user = userMapper.selectOne(
                new LambdaQueryWrapper<User>()
                        .eq(User::getUsername, username)
        );
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 返回Spring Security的User对象
        return org.springframework.security.core.userdetails.User
                .withUsername(username)
                .password(user.getPassword())  // 注意:密码应为加密后的
                .authorities(user.getRole())           // 权限
                .build();
    }
}

3.4 Spring Security + JWT 集成

创建JWT认证过滤器(JwtAuthenticationFilter):JWT认证通常是通过Authorization header传递的,需要自定义过滤器来拦截请求并验证JWT

package com.example.security;
import com.example.utils.JwtUtil;
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.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        //从请求中获取token
        String token = getTokenFromRequest(request);
        if (token != null && jwtUtil.validateToken(token)) {
            //提取用户名并加载用户信息
            String username = jwtUtil.getUsernameFromToken(token);
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            //创建认证对象并设置到安全上下文
            //创建认证token
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            //设置认证详情
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //设置Security上下文        
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(request, response);
    }
    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

配置Spring Security:SecurityConfig

  • 认证管理器AuthenticationManager:处理认证请求,登录接口使用
  • 安全过滤器链SecurityFilterChain:配置请求权限,CSRF设置
  • 密码加密PasswordEncoder:使用Bcrypt加密
package com.example.config;
import com.example.security.CustomUserDetailsService;
import com.example.security.JwtAuthenticationFilter;
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.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.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
public class SecurityConfig {
    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    //安全过滤器链
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                //禁用CSRF(跨站请求伪造)保护
                .csrf().disable()
                //配置为无状态会话
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                //配置请求的授权规则
                .authorizeRequests()
                .antMatchers("/api/users/login", "/api/users/register").permitAll()
                .antMatchers("/doc.html", "/webjars/**", "/swagger-resources/**", "/v2/api-docs", "/v3/api-docs").permitAll()
                .anyRequest().authenticated() //其他接口需要认证
                .and()
                .userDetailsService(userDetailsService) //指定自定义的用户信息服务
                //将自定义的 JWT 过滤器添加到 UsernamePasswordAuthenticationFilter 之前
                // 确保在处理用户名和密码的认证之前先进行 JWT 的验证。
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
    //认证管理器AuthenticationManager:负责处理身份验证逻辑
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception{
        return authenticationConfiguration.getAuthenticationManager();
    }
    //密码加密
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

修改UserServiceImpl,密码加密

// 在UserServiceImpl中添加
@Autowired
private PasswordEncoder passwordEncoder;
@Override
@Transactional
public boolean register(User user) {
    // 检查用户名是否已存在
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(User::getUsername, user.getUsername());
    if (userMapper.selectCount(wrapper) > 0) {
        return false;
    }
    // 密码加密
    user.setPassword(passwordEncoder.encode(user.getPassword()));
    int rows = userMapper.insert(user);
    return rows > 0;
}

修改控制器controller:处理用户登录、注册等请求并生成JWT

// 在UserController中添加
//Spring Security 认证管理器,验证用户的凭证(如用户名和密码)是否有效
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public Result<Map<String, Object>> login(@RequestBody Map<String, String> loginInfo) {
    String username = loginInfo.get("username");
    String password = loginInfo.get("password");
    // 使用Spring Security进行认证
    //基于用户名,密码的身份认证请求
    UsernamePasswordAuthenticationToken authToken = 
            new UsernamePasswordAuthenticationToken(username, password);
    //验证用户凭据
    Authentication authentication = authenticationManager.authenticate(authToken);
    //设置认证上下文
    SecurityContextHolder.getContext().setAuthentication(authentication);
    // 生成JWT令牌
    User user = userService.findByUsername(username); // 需要新增该方法
    String token = jwtUtil.generateToken(user.getId(), username);
    Map<String, Object> data = new HashMap<>();
    data.put("token", token);
    data.put("userId", user.getId());
    data.put("username", user.getUsername());
    return Result.success(data);
}

到此这篇关于SpringSecurity+JWT简单集成的实现的文章就介绍到这了,更多相关SpringSecurity JWT集成内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解SpringCloud eureka服务状态监听

    详解SpringCloud eureka服务状态监听

    这篇文章主要介绍了详解SpringCloud eureka服务状态监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • SpringBoot实现热部署的三种方式

    SpringBoot实现热部署的三种方式

    本文主要介绍了SpringBoot实现热部署的三种方式,主要包括配置pom.xml文件,使用插件的执行命令mvn spring-boot:run启动项,使用springloader本地启动修改jvm参数,使用devtools工具包,感兴趣的可以了解一下
    2023-12-12
  • 如何基于Idea远程调试tomcat war包及jar包

    如何基于Idea远程调试tomcat war包及jar包

    这篇文章主要介绍了如何基于Idea远程调试tomcat war包及jar包,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • java网上商城开发之邮件发送功能(全)

    java网上商城开发之邮件发送功能(全)

    这篇文章主要介绍了java网上商城开发之邮件发送功能,第一部分介绍了环境配置,第二部分则介绍了具体实现代码,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • Java中使用ForkJoinPool的实现示例

    Java中使用ForkJoinPool的实现示例

    ForkJoinPool是一个功能强大的Java类,用于处理计算密集型任务,本文主要介绍了Java中使用ForkJoinPool的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Java中的XML解析技术详析

    Java中的XML解析技术详析

    XML文档是一个文档树,从根部开始,并扩展到树的最底部,下面这篇文章主要给大家介绍了关于Java中XML解析技术的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-08-08
  • Java代码为例讲解堆的性质和基本操作以及排序方法

    Java代码为例讲解堆的性质和基本操作以及排序方法

    堆数据结构可以看作一颗完全二叉树,因而又被成为二叉堆,这里我们以Java代码为例讲解堆的性质和基本操作以及排序方法,需要的朋友可以参考下
    2016-06-06
  • Java异常详解_动力节点Java学院整理

    Java异常详解_动力节点Java学院整理

    异常是Java语言中的一部分,它代表程序中由各种原因引起的“不正常”因素。下面通过本文给大家介绍java异常的相关知识,感兴趣的朋友一起看看吧
    2017-06-06
  • Java中的八种基本数据类型详解

    Java中的八种基本数据类型详解

    本文详细讲解了Java中的八种基本数据类型,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • MyBatis-Plus模糊查询特殊字符串转义的实现

    MyBatis-Plus模糊查询特殊字符串转义的实现

    使用MyBatis中的模糊查询时,当查询关键字中包括有_、\、%时,查询关键字失效,本文主要介绍了MyBatis-Plus模糊查询特殊字符串转义的实现,感兴趣的可以了解一下
    2024-06-06

最新评论