原创:Java实现基于JWT的Token生成和验证(终于成功了)

原创:Java实现基于JWT的Token生成和验证(终于成功了)

为了实现这个token,我历经断断续续的差不多一个星期才解决(话说,最近我工作是真的闲,这才有时间学习),快哉,快哉。
当我一个星期前,想要在自己的项目中集成token时,思考了一下,感觉需要集成网关gateway作为前提,所以还费尽心思的在自己项目中先集成了spring cloud gateway(尴尬)。
虽然过程曲折,也不需要gateway作为前提,但是过程中还是学习到了很多很多。

好了,接下来是正题,一如既往地是保姆式的从头到尾讲解:

ps:如果要了解token的作用,请百度,这里不赘述了。

第一步是加入依赖:

 <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.5.0</version>
 </dependency>



第二步是写一个基于jwt的token帮助类,用于token生成和验证

/**
 * @Author YuanChangLiang
 * @Date 2020/11/10 20:47
 */
public class TokenUtil {
    /**
     * token过期时间
     */
    private static final long EXPIRE_TIME = 30 * 60 * 1000;
    /**
     * token秘钥
     */
    private static final String TOKEN_SECRET = "YuanChangLiang";


    /**
     * 生成签名,30分钟过期
     * @param username 用户名
     * @param loginTime 登录时间
     * @return 生成的token
     */
    public static String sign(String username, String loginTime) {
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("Type", "Jwt");
            header.put("alg", "HS256");
            // 返回token字符串
            return JWT.create()
                    .withHeader(header)
                    .withClaim("loginName", username)
                    .withClaim("loginTime", loginTime)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 检验token是否正确
     * @param token 需要校验的token
     * @return 校验是否成功
     */
    public static boolean verify(String token){
        try {
            //设置签名的加密算法:HMAC256
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e){
            return false;
        }
    }
}

第三步是登录的方法实现类

在这里插入图片描述

 /**
     * 登录
     * @param loginVo 登录类
     * @return 返回类
     */
    @Override
    public R login(LoginVo loginVo) {
        User user = new User();
        user.setUserName(loginVo.getUserName());
        user.setPassword(loginVo.getPassword());
        List<User> users = userService.queryByUser(user);
        if(users.isEmpty()){
            return R.fail();
        }else{
            if(loginVo.getUserName() != null && loginVo.getLoginTime() != null) {
                String token = TokenUtil.sign(loginVo.getUserName(), loginVo.getLoginTime());
                loginVo.setToken(token);
                //断言token不为空,并以用户名作为key,存入redis
                assert token != null;
                redisTemplate.opsForValue().set(loginVo.getUserName(),token);
                return R.ok(loginVo);
            }else{
                return R.fail();
            }
        }
    }



第四步是添加拦截器类

@Component
public class TokenInterceptor implements HandlerInterceptor {

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

        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }

        response.setCharacterEncoding("utf-8");

        String token = request.getHeader("Authorization");
        if (token != null) {
            boolean result = TokenUtil.verify(token);
            if (result) {
                System.out.println("通过拦截器");
                return true;
            }
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            JSONObject json = new JSONObject();
            json.put("success", "false");
            json.put("msg", "认证失败,未通过拦截器");
            json.put("code", "500");
            response.getWriter().append(json.toJSONString());
            System.out.println("认证失败,未通过拦截器");
        } catch (Exception e) {
            e.printStackTrace();
            response.sendError(500);
            return false;
        }
        return false;

    }
}



第五步是添加配置拦截器的类

/**
 * @author YuanChangLiang
 * @Date now
 */
@Component
public class IntercepterConfig implements WebMvcConfigurer {

    private TokenInterceptor tokenInterceptor;

    //构造方法
    public IntercepterConfig(TokenInterceptor tokenInterceptor){
        this.tokenInterceptor = tokenInterceptor;
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        List<String> excludePath = new ArrayList<>();
        //登录
        excludePath.add("/login/acount");
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
        //除了登陆接口其他所有接口都需要token验证
        WebMvcConfigurer.super.addInterceptors(registry);

    }

}



第六步在postman测试

1.先调用登录方法,获取token(ps:登录方法的返回值中要带token)

在这里插入图片描述

1.如果在请求头中不加token

在这里插入图片描述

2.如果在请求头中携带token

在这里插入图片描述



只有登录方法时不会被拦截的,其他任何请求都会要求携带token才能请求成功,可以很好的防止非法用户的恶意请求。

算了,考虑到某些没耐心,或者相对新手的道友,我给大家看看我的项目的部分结构

在这里插入图片描述
loginVo实体类

/**
 * @Author YuanChangLiang
 * @Date 2020/11/4 12:04
 */
@Data
public class LoginVo {
    /**
     * 操作码(1:注册  0:登录)
     */
    private Integer option;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 用户密码
     */
    private String password;

    /**
     * token
     */
    private String token;

    /**
     * 登录时间
     */
    private String loginTime;

}



别嫌弃我写这么详细,问就是为了适合所有人,为了让所有寻找实现token方法的道友都可以成功。
我实在是受够了这几天为了查找如何实现token,一个个的博客都是给一个token生成和验证类就完事了,掐头去尾的,其他啥也不说,阅读感觉极度极度极度差。。。。。。。。。。

----我是“道祖且长”,一个在互联网苟且偷生的Java程序员

  • 30
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

三七有脾气

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

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

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

打赏作者

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

抵扣说明:

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

余额充值