📌  相关文章
📜  从 jwt 令牌请求 Spring Boot 中获取用户名 - Java (1)

📅  最后修改于: 2023-12-03 14:49:18.117000             🧑  作者: Mango

从 JWT 令牌请求 Spring Boot 中获取用户名 - Java

在使用 Spring Boot 构建 Web 应用程序时,我们常常会使用 JWT(JSON Web Tokens)来进行认证和授权。JWT 是一种安全的、轻量级的授权令牌机制,通常在请求的 Header 中携带 JWT 令牌来进行用户认证。

本文将介绍如何通过在 Spring Boot 中解析 JWT 令牌,从中提取出用户名信息。

步骤

以下是获取 JWT 令牌中的用户名的基本步骤:

  1. 创建一个 TokenProvider 类,用于解析 JWT 令牌。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Date;

@Component
public class TokenProvider {

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

    @Value("${jwt.tokenValidity}")
    private long tokenValidity;

    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_PREFIX = "Bearer ";

    private byte[] secretKeyBytes;

    @PostConstruct
    public void init() {
        secretKeyBytes = Base64.getEncoder().encode(secretKey.getBytes());
    }

    // 生成 JWT 令牌
    public String createToken(String username) {
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + tokenValidity);

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

    // 从 HttpServletRequest 中解析 JWT 令牌
    public String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        if (bearerToken != null && bearerToken.startsWith(BEARER_PREFIX)) {
            return bearerToken.substring(BEARER_PREFIX.length());
        }
        return null;
    }

    // 验证并解析 JWT 令牌
    public boolean validateToken(String token) {
        try {
            Jwts.parser()
                    .setSigningKey(secretKeyBytes)
                    .parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            // 处理异常情况
        }
        return false;
    }

    // 从 JWT 令牌中获取用户名
    public String getUsername(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(secretKeyBytes)
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }

    // 构建 Authentication 对象
    public UsernamePasswordAuthenticationToken getAuthentication(String token) {
        if (validateToken(token)) {
            String username = getUsername(token);
            // 根据用户名构建 Authentication 对象
            // 这里可以根据业务需求自定义逻辑
            return new UsernamePasswordAuthenticationToken(username, null, null);
        }
        return null;
    }
}
  1. 在 Spring Boot 配置文件中添加 JWT 相关的配置项。
jwt.secretKey=mySecretKey
jwt.tokenValidity=86400000

在上述配置中,jwt.secretKey 是用于对 JWT 进行签名的密钥,jwt.tokenValidity 是 JWT 令牌的有效期,单位为毫秒。

  1. 创建一个 JwtFilter 类,用于过滤请求并解析 JWT 令牌。
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
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;

public class JwtFilter extends OncePerRequestFilter {

    private TokenProvider tokenProvider;

    public JwtFilter(TokenProvider tokenProvider) {
        this.tokenProvider = tokenProvider;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwtToken = tokenProvider.resolveToken(request);
        if (jwtToken != null && tokenProvider.validateToken(jwtToken)) {
            UsernamePasswordAuthenticationToken authenticationToken = tokenProvider.getAuthentication(jwtToken);
            if (authenticationToken != null) {
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}
  1. JwtFilter 添加到 Spring Security 配置中。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private TokenProvider tokenProvider;

    public SecurityConfig(TokenProvider tokenProvider) {
        this.tokenProvider = tokenProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/public").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(new JwtFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public FilterRegistrationBean<JwtFilter> jwtFilterRegistrationBean() {
        FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new JwtFilter(tokenProvider));
        // 设置过滤路径
        registrationBean.addUrlPatterns("/api/*");
        return registrationBean;
    }
}
  1. 创建一个示例的控制器,用于获取当前登录用户的用户名。
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class UserController {

    @GetMapping("/username")
    public String getUsername() {
        // 从 SecurityContext 中获取当前登录用户的用户名
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication.getName();
    }
}
  1. application.ymlapplication.properties 中配置 Spring Security 相关的配置项。这里简单配置 Basic 认证。
spring.security.user.name=admin
spring.security.user.password=s3cr3t
spring.security.user.roles=USER
  1. 运行 Spring Boot 应用程序,并发送带有 JWT 令牌的请求到 /api/username 路径,即可获取当前登录用户的用户名。
GET /api/username HTTP/1.1
Host: localhost:8080
Authorization: Bearer {JWT Token}

以上就是从 JWT 令牌中获取用户名的步骤。通过配置和修改这些代码片段,您可以根据自己的需求进行定制化开发。