Spring boot + JWT 实现安全验证 ---jjwt

参考 JWT介绍以及java-jwt的使用

JWT只是一个标准。可以通过不过的开发语言实现,包括Java,.NET, Python,Node Js, JavaScript,Perl, Ruby,Go等。
同一种语言,不同的开发者提供了多种实现库,以Java语言为例有java-jwt、?jose4j、nimbus-jose-jwt、jjwt。这里用了jjwt
 

1.在spring boot 项目中引入jwt依赖 

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.1</version>
</dependency>

 2.generate token and validation token 

import java.util.Date;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtTokenUtil {

	@Value("${jwt.issuer}")
	private String ISSUER; // project-name

	@Value("${jwt.audience}")
	private String AUDIENCE; // web

	@Value("${jwt.expires_in}")
	private int EXPIRES_IN; // 30 30min

	@Value("${jwt.header}")
	private String AUTH_HEADER; // Authorization

	private String secretKey = "project-name";

	private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;

	// generate token
	public String generateToken(Map<String, Object> claimMaps) {

		if (null != claimMaps) {
			claimMaps.forEach((key, val) -> {
				claimMaps.put(key, val.toString());
			});
		}

		return Jwts.builder()

				.setId(UUID.randomUUID().toString()) // JWT_ID
				.compressWith(CompressionCodecs.GZIP) // 数据压缩方式
				.setIssuer(ISSUER) // 签发者信息
				.setSubject("system") // 说明
				.setAudience(AUDIENCE) // 接收用户
				.setIssuedAt(new Date(System.currentTimeMillis())) // 签发时间
				.setExpiration(new Date(System.currentTimeMillis() + EXPIRES_IN * 1000 * 60)) // 过期时间戳
				.addClaims(claimMaps) // claim信息 // 自定义属性
				.signWith(SIGNATURE_ALGORITHM, secretKey) // 签名算法以及密匙
				.compact();
	}

	// validation:check if the token has expired
	public boolean isTokenExpiration(String token) {
		Claims claims = this.getAllClaimsFromToken(token);
		if (null == claims) {
			return true;
		}
		if (null == claims.getExpiration()) {
			return true;
		} else {
			return claims.getExpiration().before(new Date());
		}

	}

	// retrieve subject from token
	public String getSubjectFromToken(String token) {
		Claims claims = this.getAllClaimsFromToken(token);
		String subject = claims.getSubject();
		return subject;
	}

	// retrieve Claim from token 通过map的key值获取自定义的内容
	public String getClaimFromToken(String token) {
		Claims claims = this.getAllClaimsFromToken(token);
		String KEY = (String) claims.get("KEY");
		return KEY;
	}

	// for retrieveing any information from token we will need the secret key
	public Claims getAllClaimsFromToken(String token) {
		Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
		return claims;
	}

}

3. 把token的生成和验证工具 添加到spring 拦截器中

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class TokenInterceptor extends HandlerInterceptorAdapter {

	private JwtTokenUtil jwtTokenUtil ;

	public TokenInterceptor(JwtTokenUtil jwtTokenUtil ) {
		this.jwtTokenUtil = jwtTokenUtil ;
	}

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		String token = request.getHeader("token");
		if (null == token) {
			logger.error("token is null");
			response.setStatus(403);
			return false;
		}

		boolean isExpiration = jwtTokenUtil.isTokenExpiration(token);
		if (isExpiration) {
			logger.error("token is expiration");
			response.setStatus(403);
			return false;
		}

		String subject = jwtTokenUtil.getSubjectFromToken(token);
		if (!("system").equals(subject)) {
			logger.error("subject is not correct ");
			response.setStatus(403);
			return false;
		}

		return true;
	}

}

4.配置拦截器到项目

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

	@Autowired
	private JwtTokenUtil jwtTokenUtil ;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {

		List<String> excludePath = new ArrayList<>();
		// 获取token 不要验证
		excludePath.add("/api/generateToken");

		registry.addInterceptor(new TokenInterceptor(JwtTokenUtil ))

				.addPathPatterns("/**")

				.excludePathPatterns(excludePath);
	}

}

5.测试

用户先通过/api/generateToken获取合法的token

然后下次请求中 带着token参数就可以 获取资源

posted on 2020-06-19 18:15  dreamstar  阅读(837)  评论(0编辑  收藏  举报