Java实现Token进行登录和拦截

在应用的登录时需要生成token进行验证,并放入信息,之后的话可以直接使用浏览器的session(有时候可能会出现session共享以及丢失问题,这个时候可以使用Redis因为Redis一般集群)进行登录,获取信息,进行直接登录

这边写了一个token工具类,可以很方便的生成和解析token,代码如下

加依赖

    <dependency>
         <groupId>io.jsonwebtoken</groupId>
         <artifactId>jjwt</artifactId>
         <version>0.9.1</version> <!-- 请根据最新版本更新 -->
    </dependency>

写工具类

public class JwtUtils {

    public static final long DEFAULT_TTL = 30 * 24 * 60 * 60 * 1000L; // 30天

    public static final String DEFAULT_PLAIN_TEXT = "dbmzlh";

    /**
     * 生成UUID,也可以为雪花算法
     * @return
     */
    public static String generateUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 生成token令牌,数据为默认的
     * @return
     */
    public static String generateJWT() {
        return generateJWT(DEFAULT_PLAIN_TEXT, DEFAULT_TTL);
    }

    /**
     * 传入JSON对象生成令牌
     * @param subject
     * @return
     */
    public static String generateJWT(String subject) {
        return generateJWT(subject, DEFAULT_TTL);
    }

    /**
     * token 生成器
     * @param subject 信息
     * @param ttlMillis 有效时间
     * @return 令牌
     */
    public static String generateJWT(String subject, Long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey(); // 生成适用于 HMAC 的密钥

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = DEFAULT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);

        return Jwts.builder()
                .setId(generateUUID()) //唯一ID
                .setSubject(subject) //JSON对象
                .setIssuer("dabaimao") //签发人
                .setIssuedAt(now) //签发时间
                .signWith(signatureAlgorithm, secretKey) // 使用密钥进行签名
                .setExpiration(expDate)
                .compact();
    }

    /**
     * 使用AES算法生成公私钥
     * @return
     */
    public static SecretKey generalKey()
    {
        byte[] encodedKey = Base64.getDecoder().decode(DEFAULT_PLAIN_TEXT.replace("\r\n", ""));
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 解析token令牌
     * @param jwt 令牌
     * @return 对象
     * @throws Exception
     */
    public static Claims analysisJWT(String jwt) throws Exception
    {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }

    public static void main(String[] args) throws Exception {
        String jwtToken = generateJWT("大白猫真厉害", DEFAULT_TTL);
        System.out.println("登录成功生成的token: " + jwtToken);
​        //也可以网页解析token,网址https://jwt.io
        System.out.println("解析token得到的数据: "+analysisJWT(jwtToken).toString());
    }
}

结果如下:

61748c90cde64a8d9ca75eb15470242d.png

登录流程

第一次登录后前端将登录成功返回的token放到session中,之后每一次登录都携带session,到服务器解析生成对应的登录者数据,可以查询数据库并执行将数据放到Redis的一些操作,后端可以使用网关的过滤以及拦截去实现登录功能

拦截器实例

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(new ToKenFilter())
                 .addPathPatterns("","") //拦截那些路径
                 .excludePathPatterns(""); //放行那些路径
    }
}

在TokenFilter中处理逻辑,根据放入的数据查询Redis找到对应的人物

比如toKen免密登录解析出为user:001根据拿到的数据去数据库查询人物信息,放到Redis中

(权限验证:轻松实现权限验证 大白猫~的博客

@Component
public class ToKenFilter implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 2. 解码JWT令牌
        try {
            // 1. 从HTTP请求头部获取JWT令牌
            String jwtToken = request.getHeader("token");

            // 请替换下面的方法和密钥为你实际使用的JWT库和密钥
            Claims claims = JwtUtils.analysisJWT(jwtToken);

            // 3. 验证JWT令牌
            // 3.1 签名验证已经在解码中完成
            // 3.2 过期验证
            Date expirationDate = claims.getExpiration();
            Date now = new Date();
            if (expirationDate.before(now)) {
                // 令牌已过期,发送错误响应
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }

            // 3.3 权限验证,根据需要执行

        } catch (Exception e) {
            // 令牌无效或解码失败,发送错误响应
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        // 验证通过,返回true,请求继续到达控制器方法
        return true;
    }
}

这样就可以了

流程图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白猫~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值