下面是详细讲解Spring Boot整合JWT的实现步骤的完整攻略。
概述
JWT(JSON Web Token)是目前比较流行的身份验证和授权机制,它将用户的身份信息封装在 JSON 格式的 Token 中,在多个服务之间传递。Spring Boot是一种基于Spring框架的快速开发工具,支持构建独立的、生产级别的 Spring 应用程序。将Spring Boot和JWT集成,可以快速实现安全、简洁的前后端分离应用。
本篇攻略将详细介绍Spring Boot整合JWT的实现步骤,包括依赖引入、配置文件修改及JWT的生成和验证。
步骤一:添加依赖
在Spring Boot项目中,我们需要添加 JWT 相关的依赖,以方便开发者调用 JWT 基础功能。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
步骤二:配置文件
在Spring Boot项目中,JWT的一些相关配置可以在application.properties文件中配置。我们需要添加如下配置:
# JWT 配置
jwt.secretKey=MyJwtSecretKey
jwt.issuer=MyJwtIssuer
jwt.audience=MyJwtAudience
jwt.expiration=864000000 # 10天
- jwt.secretKey:JWT 对称加密的密钥
- jwt.issuer:JWT 签发者
- jwt.audience:JWT 接收方
- jwt.expiration:JWT 过期时间
在 application.properties 中我们也可以通过 ${} 的方式引用环境变量。
步骤三:JWT生成
接下来,我们将在Spring Boot中生成一个 JWT。在生成 JWT 之前,我们需要定义一个方法生成一个JWT Token, 示例如下:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class JwtTokenProvider {
// 加密密码
@Value("${jwt.secretKey}")
private String secretKey;
// token过期时间
@Value("${jwt.expiration}")
private long expiration;
// 签发者
@Value("${jwt.issuer}")
private String issuer;
// 颁发给
@Value("${jwt.audience}")
private String audience;
public String generateToken(String username) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + expiration);
return Jwts.builder()
.setSubject(username)
.setIssuer(issuer)
.setAudience(audience)
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact();
}
}
这里我们使用 io.jsonwebtoken.Jwts 类的 builder() 方法,将需要加密的用户信息和已有配置项参数包含在内,使用 HS512 签名算法加密生成一个JWT Token,最后使用 .compact() 方法生成一个字符串来表示JWT。如果您需要使用 RSA 或其他加密算法,请自行更改代码中的签名算法。
这是一个生成JWT Token的示例,仅适用于Demo项目。
步骤四:JWT验证
JWT 生成之后,需要在项目中添加 JWT 验证配置。我们需要在Spring Security中定义一个类,来处理传入请求时的JWT验证。 示例如下:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Value("${jwt.secretKey}")
private String secretKey;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(httpServletRequest);
if (StringUtils.hasText(jwt) && validateToken(jwt)) {
//获取JWT的Claims
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
String username = claims.getSubject();
List<String> authorities = Arrays.asList(claims.get("authorities").toString().split(","));
List<SimpleGrantedAuthority> simpleGrantedAuthorities = authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
UserDetails userDetails = new User(username, "", simpleGrantedAuthorities);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
private Boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return true;
} catch (SignatureException ex) {
logger.error("Invalid JWT signature");
} catch (Exception ex) {
logger.error("Invalid JWT token");
}
return false;
}
}
在这段代码里我们需要继承 Spring Security 中的 OncePerRequestFilter 类,并重写 doFilterInternal 方法,在这个方法中,我们判断传入的请求中是否携带了JWT Token,如果有就将其和加密的Secret Key 对比验证,然后将验证成功的用户ID存储在 Spring Security 的上下文(Context)中。
我们需要通过 JWT Token 的 Claims 方法获取Token中的信息,将其封装在 UserDetails 中,然后再通过 Spring Security 的上下文存储,在后续我们可以使用 UserDetails 获取用户的相关信息。
示例代码
在实现步骤中给出的示例代码,需要注意以下几点:
-
此示例代码是基于 Spring Boot 和 Spring Security 来实现的,需要一定的 Spring Boot 开发经验。如果您对 Spring Boot 和 Spring Security 不熟悉,需要先学习相关知识。
-
示例代码是基于前后端分离架构,并且使用了JWT作为身份认证和授权机制。因此您还需要学习前后端分离架构和JWT相关知识。
-
示例代码仅适用于Demo项目,未经过严格测试,不适用于生产环境代码,建议使用时进行适度修改。
Demo项目源码可以在github上找到:Spring-Boot-JWT Example
以上就是 Spring Boot整合JWT的实现步骤的完整攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Boot整合JWT的实现步骤 - Python技术站