小程序登录(二)——通过JWT实现权限认证

JWT 是一个开放标准,它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名
简单来说,就是通过一定规范来生成token,然后可以通过解密算法逆向解密token,这样就可以获取用户信息

实现流程:

  1. 将用户信息加密生成token,响应给前端,前端将token存储在localstorage中,之后访问需要权限的接口,都将token保存在请求头中。
  2. 使用AOP对权限接口进行横向拦截,将token解密,存储在TheadLocal中,后面执行的方法就能通过TheadLocal获取用户信息了,由于token会存储在前端,建议使用https协议。

Maven依赖:


	io.jsonwebtoken
	jjwt
	0.9.0

JWTUtil

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.crypto.MacProvider;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.UUID;

/**
 * JWT校验工具类
 * 
    *
  1. iss: jwt签发者
  2. *
  3. sub: jwt所面向的用户
  4. *
  5. aud: 接收jwt的一方
  6. *
  7. exp: jwt的过期时间,这个过期时间必须要大于签发时间
  8. *
  9. nbf: 定义在什么时间之前,该jwt都是不可用的
  10. *
  11. iat: jwt的签发时间
  12. *
  13. jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
  14. *
*/ @Log4j2 public class JwtUtil { /** * JWT 加解密类型 */ private static final SignatureAlgorithm JWT_ALG = SignatureAlgorithm.HS256; /** * JWT 生成密钥使用的密码 */ private static final String JWT_RULE = "XXX"; /** * JWT 添加至HTTP HEAD中的前缀 */ private static final String JWT_SEPARATOR = "Bearer "; /** * 使用JWT默认方式,生成加解密密钥 * * @param alg 加解密类型 * @return */ public static SecretKey generateKey(SignatureAlgorithm alg) { return MacProvider.generateKey(alg); } /** * 使用指定密钥生成规则,生成JWT加解密密钥 * * @param alg 加解密类型 * @param rule 密钥生成规则 * @return */ public static SecretKey generateKey(SignatureAlgorithm alg, String rule) { // 将密钥生成键转换为字节数组 byte[] bytes = Base64.decodeBase64(rule); // 根据指定的加密方式,生成密钥 return new SecretKeySpec(bytes, alg.getJcaName()); } /** * 构建JWT * * @param alg jwt 加密算法 * @param key jwt 加密密钥 * @param sub jwt 面向的用户 * @param aud jwt 接收方 * @param jti jwt 唯一身份标识 * @param iss jwt 签发者 * @param nbf jwt 生效日期时间 * @param duration jwt 有效时间,单位:秒 * @return JWT字符串 */ public static String buildJWT(SignatureAlgorithm alg, Key key, String sub, String aud, String jti, String iss, Date nbf, Integer duration) { // jwt的签发时间 DateTime iat = DateTime.now(); // jwt的过期时间,这个过期时间必须要大于签发时间 DateTime exp = null; if (duration != null) exp = (nbf == null ? iat.plusSeconds(duration) : new DateTime(nbf).plusSeconds(duration)); // 获取JWT字符串 String compact = Jwts.builder() .signWith(alg, key) .setSubject(sub) .setAudience(aud) .setId(jti) .setIssuer(iss) .setNotBefore(nbf) .setIssuedAt(iat.toDate()) .setExpiration(exp != null ? exp.toDate() : null) .compact(); // 在JWT字符串前添加"Bearer "字符串,用于加入"Authorization"请求头 return JWT_SEPARATOR + compact; } /** * 构建JWT * * @param sub jwt 面向的用户 * @param aud jwt 接收方 * @param jti jwt 唯一身份标识 * @param iss jwt 签发者 * @param nbf jwt 生效日期时间 * @param duration jwt 有效时间,单位:秒 * @return JWT字符串 */ public static String buildJWT(String sub, String aud, String jti, String iss, Date nbf, Integer duration) { return buildJWT(JWT_ALG, generateKey(JWT_ALG, JWT_RULE), sub, aud, jti, iss, nbf, duration); } /** * 构建JWT * * @param sub jwt 面向的用户 * @param jti jwt 唯一身份标识,主要用来作为一次性token,从而回避重放攻击 * @return JWT字符串 */ public static String buildJWT(String sub, String jti, Integer duration) { return buildJWT(sub, null, jti, null, null, duration); } /** * 构建JWT *

使用 UUID 作为 jti 唯一身份标识

*

JWT有效时间 600 秒,即 10 分钟

* * @param sub jwt 面向的用户 * @return JWT字符串 */ public static String buildJWT(String sub) { return buildJWT(sub, null, UUID.randomUUID().toString(), null, null, 600); } /** * 解析JWT * * @param key jwt 加密密钥 * @param claimsJws jwt 内容文本 * @return {@link Jws} * @throws Exception */ public static Jws parseJWT(Key key, String claimsJws) { // 移除 JWT 前的"Bearer "字符串 claimsJws = StringUtils.substringAfter(claimsJws, JWT_SEPARATOR); // 解析 JWT 字符串 return Jwts.parser().setSigningKey(key).parseClaimsJws(claimsJws); } /** * 校验JWT * * @param claimsJws jwt 内容文本 * @return ture or false */ public static Boolean checkJWT(String claimsJws) { boolean flag = false; try { SecretKey key = generateKey(JWT_ALG, JWT_RULE); // 获取 JWT 的 payload 部分 flag = (parseJWT(key, claimsJws).getBody() != null); } catch (Exception e) { log.warn("JWT验证出错,错误原因:{}", e.getMessage()); } return flag; } /** * 校验JWT * * @param key jwt 加密密钥 * @param claimsJws jwt 内容文本 * @param sub jwt 面向的用户 * @return ture or false */ public static Boolean checkJWT(Key key, String claimsJws, String sub) { boolean flag = false; try { // 获取 JWT 的 payload 部分 Claims claims = parseJWT(key, claimsJws).getBody(); // 比对JWT中的 sub 字段 flag = claims.getSubject().equals(sub); } catch (Exception e) { log.warn("JWT验证出错,错误原因:{}", e.getMessage()); } return flag; } /** * 校验JWT * * @param claimsJws jwt 内容文本 * @param sub jwt 面向的用户 * @return ture or false */ public static Boolean checkJWT(String claimsJws, String sub) { return checkJWT(generateKey(JWT_ALG, JWT_RULE), claimsJws, sub); } }

登录权限拦截

import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

/**
 * 请求鉴权拦截器
 */
@Log4j2
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {

    private static ThreadLocal currentUser=new ThreadLocal<>();

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

        // 获取 HTTP HEAD 中的 TOKEN
        String authorization = request.getHeader("Authorization");
        if(StringUtils.isBlank(authorization){
        	// 如果校验未通过,返回 401 状态
        	 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        	 return false;
        }
        // 校验 TOKEN
       try{
            String userId= JWTUtil.parseJWT(authorization).getBody().getSubject();
            currentUser.set(userId);
            return true;
       }catch(Exception e){
	       // 如果校验未通过,返回 401 状态
		   response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
           return false;
	   }
   }
}

你可能感兴趣的:(微信小程序,微信小程序)