【微服务环境配置JWT】SpringBoot中配置jwt

2023-04-06 09:27:29 浏览数 (1)

1. 在微服务父工程中pom文件中引入,jwtToken依赖

代码语言:javascript复制
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

2. 配置创建JwtToken的工具类

代码语言:javascript复制
package priv.kuki.utils;

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

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;

/**
 * @author Tang-J-L
 * @Description JwtUtil
 * @Date 2023/4/3 周一 19:18
 */
public class JwtUtil{

    /**
     * 默认有效期 30min
     */
    public static final Long JWT_TTL = 3600000L;

    /**
     * jwt令牌信息
     */
    public static final String JWT_KEY = "Tang-J-L";

    /**
     * 创建令牌
     * @param id 令牌唯一标识
     * @param subject 主题信息
     * @param ttlMillis 有效期
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis){

        // 指定算法
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 系统当前时间
        long nowMillis = System.currentTimeMillis();

        // 令牌颁发时间
        Date now = new Date(nowMillis);

        // 若传入的令牌有效期为null,则使用默认有效期
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }

        // 令牌过期时间
        long expMillis = nowMillis   ttlMillis;
        Date expDate = new Date(expMillis);

        // 生成密钥
        SecretKey secretKey = generalKey();

        // 封装令牌信息
        JwtBuilder jwtBuilder = Jwts.builder()
                .setId(id) //令牌唯一标识
                .setSubject(subject) // 主题,可以是JSON数据
                .setIssuer("Tang-J-L") // 签发者
                .setIssuedAt(now) // 签发时间
                .signWith(signatureAlgorithm, secretKey) // 签名以及密钥.参1:签名算法;参2:密钥(盐)
                .setExpiration(expDate);// 设置过期时间

        return jwtBuilder.compact();
/*         // 令牌过期时间设置
        long expMillis = nowMillis   ttlMillis;
        Date expDate = new Date(expMillis);

        // 构建jwt令牌
        JwtBuilder jwtBuilder = Jwts.builder();
        // jwt颁发者
        jwtBuilder.setIssuer("酷奇");
        // 颁发日期
        jwtBuilder.setIssuedAt(new Date());
        // 主题信息
        jwtBuilder.setSubject("jwt令牌");
        // 签名。参1:签名算法;参2:密钥(盐)
        jwtBuilder.signWith(SignatureAlgorithm.HS256,"Tang-J-L");
        // 过期时间,一般为30分钟,当前系统时间   30min
        jwtBuilder.setExpiration(new Date(System.currentTimeMillis()   1800000));
        // 自定义载荷信息,添加附加信息
        HashMap<String, Object> userInfo = new HashMap<>();
        userInfo.put("company","CODER");
        userInfo.put("vip","coder-v");
        // 将自定义信息添加到令牌中
        jwtBuilder.addClaims(userInfo);

        // 生成jwtToken
        String token = jwtBuilder.compact(); */

    }

    /**
     * 生成加密 generalKey:对当前密钥进行再次Base64加密
     * @return
     */
    public static SecretKey generalKey(){
        byte[] encodeKey = Base64.getEncoder().encode(JwtUtil.JWT_KEY.getBytes());
        SecretKey key = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
        return key;
    }


    /**
     * 解析令牌
     */
    public static Claims parseJWT(String jwt){
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
        /**
         * setSigningKey():解析密钥
         * parseClaimsJws():解析token
         * getBody():获取解析后的数据
         * toString():讲解析后的令牌转换为String得到最终的令牌
         */
        // Claims jwtToken = Jwts.parser().setSigningKey("Tang-J-L").parseClaimsJws().getBody().toString();
    }
}

3. 创建用户鉴权的工具类

代码语言:javascript复制
package priv.kuki.utils;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.lang.annotation.Annotation;

/**
 * @author Tang-J-L
 * @Description 用户权限校验
 * @Date 2023/4/3 周一 20:44
 */
@Component
public class AuthorizeFilter implements GlobalFilter, Order{

    /**
     * 令牌名字
     */
    public static final String AUTHORIZE_TOKEN = "Authorization";

    /**
     * 全局拦截
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 获取令牌信息:令牌可能在 1)参数中, 2)请求头中, 3)Cookie中
        // 1)从 请求头中 获取
        String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);
        // 出于微服务原因,其他服务需要从请求头中获取token,若前台不是放在请求头中,则我们需要将其封装到请求头中
        boolean hasToken = true;

        // 2)从 参数中 获取
        if (StringUtils.isEmpty(token)) {
            token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
            hasToken = false;
        }

        // 3)从 Cookie中 获取
        if (StringUtils.isEmpty(token)) {
            HttpCookie httpCookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);
            if (httpCookie != null) {
                token = httpCookie.getValue();
            }
        }

        // 若没有令牌则拦截
        if(StringUtils.isEmpty(token)){
            // 设置没有权限的状态码 401
            // response.setStatusCode(HttpStatus.UNAUTHORIZED);
            R.fail("你还没有登录",token);
            // 响应空数据
            return response.setComplete();
        }

        // 若有令牌,则校验令牌是否有效
        try{
            JwtUtil.parseJWT(token);
        }catch(Exception e) {
            // 无效则拦截
            // 设置没有权限的状态码 401
            // response.setStatusCode(HttpStatus.UNAUTHORIZED);
            R.fail("你还没有登录",e);
            // 响应空数据
            return response.setComplete();
        }

        // 将令牌封装到请求头中,在其他微服务中通过 OAuthor 框架鉴权
        request.mutate().header(AUTHORIZE_TOKEN, token);

        // 有效则放行
        return chain.filter(exchange);
    }

    /**
     * @return
     */
    @Override
    public int value(){
        return 0;
    }

    /**
     * Returns the annotation type of this annotation.
     *
     * @return the annotation type of this annotation
     */
    @Override
    public Class<? extends Annotation> annotationType(){
        return null;
    }
}

4. 用户登录成功后创建jwtToken,并将token信息返回给前端

代码语言:javascript复制
		// 创建jwtToken
		// 创建token以外的自定义额外信息
        Map<String,Object> tokenMap = new HashMap<>();
        tokenMap.put("role","USER");
        tokenMap.put("success","SUCCESS");
        tokenMap.put("username",user.getUserName());
        String token = JwtUtil.createJWT(
                UUID.randomUUID().toString(), // uuid作为令牌id
                JSONUtils.toJSONString(tokenMap), // 令牌中的额外信息
                1800000L // 过期时间 30min
        );

        // 把令牌信息存入Cookie
        Cookie cookie = new Cookie("Authorization", token);
        // 所属域名
        cookie.setDomain("localhost");
        // 根路径
        cookie.setPath("/");

        // 将令牌存入Cookie响应给前端
        response.addCookie(cookie);

        // 把令牌作为信息返回给客户端
        return R.ok("登录成功!",cookie);

0 人点赞