All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.smallbun.scaffold.framework.security.jwt.TokenProvider Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2018-2019.‭‭‭‭‭‭‭‭‭‭‭‭[zuoqinggang] www.pingfangushi.com
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package cn.smallbun.scaffold.framework.security.jwt;

import cn.smallbun.scaffold.framework.configurer.SmallBunProperties;
import cn.smallbun.scaffold.framework.security.domain.User;
import com.google.common.collect.Lists;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * 令牌提供者
 * @author SanLi
 * Created by [email protected] / [email protected] on  2019/5/7
 */
public class TokenProvider implements InitializingBean {

	private final Logger logger = LoggerFactory.getLogger(TokenProvider.class);
	/**
	 * authorities
	 */
	private static final String AUTHORITIES_KEY = "AUTHORITIES";
	/**
	 * 用户ID
	 */
	private static final String USER_ID = "USER_ID";
	/**
	 * 加密key
	 */
	private Key key;
	/**
	 * 令牌有效性(以毫秒为单位)
	 */
	private long tokenValidityInMilliseconds;
	/**
	 * 记住我的令牌有效性(以毫秒为单位)
	 */
	private long tokenValidityInMillisecondsForRememberMe;

	public TokenProvider(SmallBunProperties properties) {
		this.security = properties.getSecurity();
	}

	@Override
	public void afterPropertiesSet() {
		byte[] keyBytes;
		String secret = security.getAuthentication().getJwt().getSecret();
		if (!StringUtils.isEmpty(secret)) {
			logger.warn("警告:使用的JWT密钥不是Base64编码的. "
					+ "我们建议使用`cn.smallbun.scaffold.security.authentication.jwt.base64-secret`密钥以获得最佳安全性.");
			keyBytes = secret.getBytes(StandardCharsets.UTF_8);
		} else {
			logger.debug("使用Base64编码的JWT密钥");
			keyBytes = Decoders.BASE64.decode(security.getAuthentication().getJwt().getBase64Secret());
		}
		this.key = Keys.hmacShaKeyFor(keyBytes);
		this.tokenValidityInMilliseconds = 1000 * security.getAuthentication().getJwt().getTokenValidityInSeconds();
		this.tokenValidityInMillisecondsForRememberMe =
				1000 * security.getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe();
	}

	/**
	 * 创建token
	 * @param authentication {@link Authentication} authentication 授权
	 * @param rememberMe {@link Boolean} rememberMe 是否记住我
	 * @return token
	 */
	public String createToken(Authentication authentication, boolean rememberMe) {
		//权限
		String auth = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority)
				.collect(Collectors.joining(","));
		long now = (new Date()).getTime();
		Date validity;
		//是否记住我
		if (rememberMe) {
			validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
		} else {
			validity = new Date(now + this.tokenValidityInMilliseconds);
		}
		//封装JWT
		JwtBuilder builder = Jwts.builder().setSubject(authentication.getName())
				//设置自定义JWT Claims参数值。这里放置权限集合
				.claim(AUTHORITIES_KEY, auth)
				//用户ID
				.claim(USER_ID, ((User) authentication.getPrincipal()).getId())
				//签名
				.signWith(key, SignatureAlgorithm.HS512)
				//过期时间
				.setExpiration(validity);
		return builder.compact();
	}

	/**
	 * 获得身份验证
	 * @param token token
	 * @return  {@link Authentication}
	 */
	Authentication getAuthentication(String token) {
		//获取Claims
		Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
		//获取权限
		Collection authorities = Lists.newArrayList();
		//有权限的时候处理权限、没有不处理
		if (!StringUtils.isEmpty(claims.get(AUTHORITIES_KEY).toString())) {
			authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
					.map(SimpleGrantedAuthority::new).collect(Collectors.toList());
		}
		//封装用户
		User user = new User(claims.getSubject(), "", claims.get(USER_ID).toString(), authorities);
		//返回认证
		return new UsernamePasswordAuthenticationToken(user, token, authorities);
	}

	/**
	 * 验证token
	 * @param authToken token
	 * @return 是否通过
	 */
	boolean validateToken(String authToken) {
		try {
			Jwts.parser().setSigningKey(key).parseClaimsJws(authToken);
			return true;
		} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
			logger.info("Invalid JWT signature.");
			logger.trace("Invalid JWT signature trace: {}", e);
		} catch (ExpiredJwtException e) {
			logger.info("Expired JWT token.");
			logger.trace("Expired JWT token trace: {}", e);
		} catch (UnsupportedJwtException e) {
			logger.info("Unsupported JWT token.");
			logger.trace("Unsupported JWT token trace: {}", e);
		} catch (IllegalArgumentException e) {
			logger.info("JWT token compact of handler are invalid.");
			logger.trace("JWT token compact of handler are invalid trace: {}", e);
		}
		return false;
	}

	private final SmallBunProperties.Security security;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy