Java - SpringBoot整合JWT

24 篇文章 8 订阅
6 篇文章 0 订阅

前言

Java - JWT的简单介绍和使用

一. SpringBoot整合JWT

1.1 基础配置

1.pom依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
</parent>
<dependencies>
	<!-- 配置类的一个支持注解 -->
	<dependency>
	   <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-configuration-processor</artifactId>
	    <optional>true</optional>
	</dependency>
	<!-- JWT相关 -->
	<dependency>
	    <groupId>com.auth0</groupId>
	    <artifactId>java-jwt</artifactId>
	    <version>3.19.1</version>
	</dependency>
	<dependency>
	    <groupId>io.jsonwebtoken</groupId>
	    <artifactId>jjwt</artifactId>
	    <version>0.7.0</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<!-- 工具类 -->
	<dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
    <!-- 省略get/set等方法 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

2.application.yml文件:

server:
  port: 8080

config:
  jwt:
    secret: ASD!@#F^%A
    expire: 600

1.2 Token配置类

Token配置类JwtUtil

@Component
@Data
@ConfigurationProperties(prefix = "config.jwt")
public class JwtUtil {
    private String secret;
    private int expire;

    public String buildToken(Long userId) {
        Calendar expires = Calendar.getInstance();
        expires.add(Calendar.SECOND, expire);

        String token = JWT
                .create()
                .withSubject(String.valueOf(userId))
                .withExpiresAt(expires.getTime())
                // 第三部分Signature
                .sign(Algorithm.HMAC256(secret));
        return token;
    }

    public Long getSubject(String token) {
        Long res = null;
        if (StringUtils.isBlank(token)) {
            return res;
        }
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
        // 验证失败会抛出异常
        DecodedJWT verify = verifier.verify(token);

        String subject = verify.getSubject();
        if (StringUtils.isNoneBlank(subject)) {
            res = Long.parseLong(subject);
        }
        return res;
    }
}
  • @ConfigurationProperties(prefix = "config.jwt"):用于获取配置文件中的属性定义并绑定到Bean的属性中。
  • @Data:因为属性的装配注入,需要依赖于对应的get/set方法。因此通过这个注解来快速实现get/set

TokenContext类,用来存储userId,这样当次请求就可以在任意一个地方拿到这个变量了。

public class TokenContext {
    public static final ThreadLocal<Long> USER_ID = new ThreadLocal<>();

    public static Long getUserId() {
        return USER_ID.get();
    }

    public static void setUserId(Long userId) {
        USER_ID.set(userId);
    }

    public static void clear(){
        USER_ID.remove();
    }
}

1.3 拦截器的注册

拦截器TokenInterceptor

@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
 	// 过滤登录等特殊请求地址,真实情况要比这个多的多,比如静态资源的等等。
 	// Header的key
    public static final String LOGIN_URL = "/login";
    public static final String TOKEN = "token";

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        // 排除登录等特殊请求
        if (requestURI.contains(LOGIN_URL)) {
            return true;
        }
        String token = request.getHeader(TOKEN);
        if (StringUtils.isBlank(token)) {
            throw new SignatureException("Token不能为空!");
        }
        // 获取JWT中存储的userId
        Long userId = jwtUtil.getSubject(token);
        if (userId == null) {
            throw new SignatureException("Token失效,请重新登录!");
        }
        TokenContext.setUserId(userId);
        return true;
    }
}

WebMvc配置WebConfig:配置拦截器生效。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private TokenInterceptor tokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
    }
}

1.4 异常类处理和接口实现

写一个异常类处理ExceptionController

@RestControllerAdvice
public class ExceptionController {
    @ExceptionHandler(value = {SignatureException.class})
    @ResponseBody
    public String authorizationException(SignatureException e) {
        return e.getMessage();
    }
}

写两个接口:

@RestController
public class MyController {
    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public String login(@RequestParam("userId") Long userId) {
        String token = jwtUtil.buildToken(userId);
        return "Success, Jwt Token : " + token;
    }

    @PostMapping("/getUser")
    public String getUser() {
        try {
            Long userId = TokenContext.getUserId();
            if (userId != null) {
                return "成功拿到用户信息: " + userId;
            }
            return "用户信息为空";
        } finally {
            TokenContext.clear();
        }
    }
}

1.5 测试

登录结果如下:
在这里插入图片描述


测试带Token请求:

在这里插入图片描述

测试不带Token请求:

在这里插入图片描述

文章到这里就结束啦,后面会出一篇文章,整合Shiro + JWT + SpringCloudSpringBoot

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以通过以下步骤在Spring Boot中集成JWT: 1. 添加java-jwt依赖包到pom.xml文件中: ```xml <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.1</version> </dependency> ``` 2. 创建一个JWT工具类来生成和验证JWT令牌: ```java import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import java.util.Date; public class JwtUtils { private static final long EXPIRATION_TIME = 86400000; // 24 hours private static final String SECRET = "mySecret"; private static final String ISSUER = "myIssuer"; public static String generateToken(String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); return JWT.create() .withSubject(username) .withIssuer(ISSUER) .withIssuedAt(now) .withExpiresAt(expiryDate) .sign(Algorithm.HMAC512(SECRET)); } public static String getUsernameFromToken(String token) throws JWTVerificationException { DecodedJWT jwt = JWT.require(Algorithm.HMAC512(SECRET)) .withIssuer(ISSUER) .build() .verify(token); return jwt.getSubject(); } } ``` 3. 在Spring Security配置中添加JWT过滤器,以验证JWT令牌: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Configuration @Order(1) public class JwtConfig extends SecurityConfigurerAdapter<javax.servlet.Filter, HttpSecurity> { @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; @Override public void configure(HttpSecurity http) throws Exception { JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(); jwtAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); jwtAuthenticationFilter.setAuthenticationFailureHandler(new JwtAuthenticationFailureHandler()); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } private class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { throw new JwtAuthenticationException("Invalid JWT token"); } String username = JwtUtils.getUsernameFromToken(token.substring(7)); if (username == null) { throw new JwtAuthenticationException("Invalid JWT token"); } return jwtAuthenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(username, "")); } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { super.successfulAuthentication(request, response, chain, authResult); chain.doFilter(request, response); } } private class JwtAuthenticationFailureHandler extends HttpStatusEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setStatus(HttpStatus.UNAUTHORIZED.value()); } } } ``` 4. 创建一个JwtAuthenticationProvider来验证用户名和密码: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @Component public class JwtAuthenticationProvider implements AuthenticationProvider { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = (String) authentication.getCredentials(); UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (!passwordEncoder.matches(password, userDetails.getPassword())) { throw new JwtAuthenticationException("Invalid username or password"); } return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities()); } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } } ``` 5. 在Spring Security配置中添加JwtConfig: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(jwtAuthenticationProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .antMatcher("/**") .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .apply(new JwtConfig()); } } ``` 现在你就可以在Spring Boot应用程序中使用JWT进行身份验证了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Zong_0915

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

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

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

打赏作者

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

抵扣说明:

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

余额充值