SpringBoot整合JWT实现安全认证

Spring Boot 整合 JWT 实现一个安全的Restful 接口?

JWT 是一种用于身份验证和授权的开放标准(RFC 7519),它允许使用签名验证和信息加密来传输数据。集成 JSON Web Token(JWT)到 Spring Boot 以实现安全的 RESTful 接口是一种常见的做法。下面是一个简单的步骤,展示如何在 Spring Boot 中整合 JWT。

第一步、添加POM依赖

首先,需要添加JWT相关依赖到POM文件中。这里需要根据自己项目的版本对JWT版本做对应的适配,否则可能会出现版本差异导致相关功能不能用的情况出现。

复制代码
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>

创建JWT工具类

需要创建一个JWT的通用工具类,完成JWT的创建与解析操作,同时需要完成认证的签发、验证令牌等操作。如下所示。

复制代码
@Component
public class JwtUtils {

    private static final String SECRET_KEY = "yourSecretKey";
    private static final long EXPIRATION_TIME = 86400000; // 24 hours

    public String generateToken(String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);

        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();

        return claims.getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }
}

注意这里需要指定对应的秘钥以及过期时间等信息。

创建接口安全配置类

引入SpringSecurity的POM依赖

复制代码
<!-- spring security 安全认证 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

创建配置类

创建一个 Spring Security 配置类,配置认证和授权规则,并且集成 JWT。

复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // 配置用户认证信息
        auth.inMemoryAuthentication()
                .withUser("admin").password(passwordEncoder().encode("password")).roles("ADMIN")
                .and()
                .withUser("user").password(passwordEncoder().encode("password")).roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/authenticate").permitAll()
            .antMatchers(HttpMethod.GET, "/api/**").hasAnyRole("USER", "ADMIN")
            .antMatchers(HttpMethod.POST, "/api/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

需要注意,这里提供了一个

UsernamePasswordAuthenticationFilter的拦截器,这个拦截器就是用来进行请求拦截进行判断处理的。

复制代码
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
    @Autowired
    private JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException{
              // 具体使用 
              // 1、通过Request请求获取到请求头中的Token信息
              // 2、将Token信息传入到JwtUtils进行认证,如果通过则继续调用
              // 如果拦截返回未授权信息
        chain.doFilter(request, response);
    }
}

创建认证请求实体对象

创建一个通用的认证请求以及相应对象来进行测试调用。

复制代码
public class AuthRequest {

    private String username;
    private String password;

    // getters and setters
}

public class AuthResponse {

    private final String token;

    public AuthResponse(String token) {
        this.token = token;
    }

    // getter
}

创建 REST 控制器

创建 REST 控制器来处理认证请求,并且使用 JWT 工具类来生成令牌。

复制代码
@RestController
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @PostMapping("/authenticate")
    public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthRequest authenticationRequest) throws Exception {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword()));
        } catch (AuthenticationException e) {
            throw new Exception("Incorrect username or password", e);
        }

        final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
        final String token = jwtUtils.generateToken(userDetails.getUsername());

        return ResponseEntity.ok(new AuthResponse(token));
    }
}

创建完成之后,就可以通过接口调用认证接口,然后获取到认证的Token令牌,然后根据访问令牌来进行身份验证,这样就可以保证接口调用的安全性。

相关推荐
AskHarries4 分钟前
用 OpenClaw 做数据分析报告:CSV / Excel 到可视化结果
程序员
两万五千个小时18 分钟前
Claude Code 上下文管理(二):零 Token 消耗的压缩三板斧
人工智能·程序员·开源
用户37215742613540 分钟前
Java 将 Word 文档转换为 Markdown:基础转换与导出选项详解
java
行者全栈架构师1 小时前
PolarDB + Spring Boot 实战:从自建MySQL到云原生数据库的零停机迁移
java·后端·架构
陈随易13 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
karry_k17 小时前
MyBatis批量insert-select踩坑:useGeneratedKeys=true 可能让PostgreSQL返回大量插入结果
java·后端
karry_k17 小时前
PostgreSQL 在 MyBatis 中执行正常 SQL 失效:一次 DELETE USING 踩坑记录
java·后端
这个DBA有点耶18 小时前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
Larcher20 小时前
从零搭建 MCP 服务——让 AI 拥有无限扩展能力
人工智能·程序员
SamDeepThinking21 小时前
从源码到代码:MyBatis-Flex 与 MyBatis-Plus 的逐项对比
java·后端·程序员