token的使用

 Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。


JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,JWT是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。


引入maven依赖

        <!-- JSON Web Tokens jar -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.8.0</version>
        </dependency>

编写jwt工具类,用于生成token,解析token,代码如下:

/**
 * @author 2019 shiwq
 * 获取token工具类
 */
public class JwtHelper {

    /**
     * 传入用户ID,设备信息,封装到token中
     *
     * @param userId 用户id
     * @return token token
     * @throws Exception
     */
    public String createTokenWithClaim(long userId, String deviceInfo) throws Exception {
        //签名,自定义即可
        Algorithm algorithm = Algorithm.HMAC256("****");
        //token的HEADER
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        //15天过期
        Date nowDate = new Date();
        Date expireDate = getAfterDate(nowDate, 0, 0, 15, 0, 0, 0);
        String token = JWT.create()
                /*设置头部信息 Header*/
                .withHeader(map)
                /*设置 载荷 Payload*/
                //设备信息
                .withClaim("deviceInfo", deviceInfo)
                //用户ID
                .withClaim("userId", userId)
                //签名是有谁生成  例如 服务器
                .withIssuer("SERVICE")
                //签名的主题
                .withSubject("login")
                //定义在什么时间之前,该jwt都是不可用的.
                //.withNotBefore(new Date())
                //签名的观众 也可以理解谁接受签名的
                .withAudience("aoBaoSystem")
                //生成签名的时间
                .withIssuedAt(nowDate)
                //签名过期的时间
                .withExpiresAt(expireDate)
                /*签名 Signature */
                .sign(algorithm);
        JwtHelper jwtHelper = new JwtHelper();
        return token;
    }

    /**
     * 返回一定时间后的日期
     *
     * @param date   开始计时的时间
     * @param year   增加的年
     * @param month  增加的月
     * @param day    增加的日
     * @param hour   增加的小时
     * @param minute 增加的分钟
     * @param second 增加的秒
     * @return
     */
    public Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second) {
        if (date == null) {
            date = new Date();
        }

        Calendar cal = new GregorianCalendar();

        cal.setTime(date);
        if (year != 0) {
            cal.add(Calendar.YEAR, year);
        }
        if (month != 0) {
            cal.add(Calendar.MONTH, month);
        }
        if (day != 0) {
            cal.add(Calendar.DATE, day);
        }
        if (hour != 0) {
            cal.add(Calendar.HOUR_OF_DAY, hour);
        }
        if (minute != 0) {
            cal.add(Calendar.MINUTE, minute);
        }
        if (second != 0) {
            cal.add(Calendar.SECOND, second);
        }
        return cal.getTime();
    }

    /**
     * 将用户ID和设备信息,过期时间封装到map中返回
     *
     * @param token token 传入token
     * @return 返回map,包含载荷信息,这里设置的是用户id和设备信息
     * @throws Exception
     */
    public Map<String, Object> verifyToken(String token) throws Exception {
        Algorithm algorithm = Algorithm.HMAC256("****");
        JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer("SERVICE")
                .build(); //Reusable verifier instance
        DecodedJWT jwt = verifier.verify(token);
        String subject = jwt.getSubject();
        Map<String, Claim> claims = jwt.getClaims();
        long userId = claims.get("userId").asLong();
        String deviceInfo = claims.get("deviceInfo").asString();
        Date expireDate = jwt.getExpiresAt();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userId", userId);
        map.put("deviceInfo", deviceInfo);
        map.put("expireDate", expireDate);
        return map;
    }
}

使用实例,登录后签发token

@Override
    public ResponseResult loginByPassword(String userCode, String password, String deviceInfo) throws Exception {
        //获取用户信息
        UserInfo userInfo;
        //前置代码不展示,正常逻辑走完后,进入token生成,并保存
        if (true) {
            JwtHelper jwtHelper = new JwtHelper();
            //签发token
            String token = jwtHelper.createTokenWithClaim(userInfo.getUserId(), deviceInfo);
            //保存token到数据库
            if (userLoginMapper.updateToken(userInfo.getUserId(), token) > 0) {
                //token保存成功,返回前台
                return new ResponseResult("success", "登陆成功", userInfo);
        }
        return new ResponseResult("error", "密码错误", null);
    }

客户端拿到token后,每次请求将token带上,服务端的拦截器拦截并处理请求是否合法

 @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding("UTF-8");
        String token = request.getHeader("Authorization");
        String deviceId = request.getHeader("deviceId");
        JwtHelper jwtHelper = new JwtHelper();
        PrintWriter out = null;
        try {
            Map<String, Object> map = jwtHelper.verifyToken(token);
            //获取token中的用户id
            long userId = (long) map.get("userId");
            //从数据库中获取用户信息
            UserLogin userLogin = userLoginMapper.getUserLogin(userId);
            out = response.getWriter();
            if(userLogin == null){
                out.append(JSON.toJSONString(new ResponseResult("error", "token验证不通过", null)));
                return false;
            }
            String deviceInfo = map.get("deviceInfo").toString();
            //校验token是否过期
            //这里我只做了简单的userId校验和过期时间校验,各位可以根据实际情况增加或减少相应的条件校验
            Date expireDate = (Date) map.get("expireDate");
            //判断当前请求的设备信息和token包含的设备信息是否一致
            if (deviceId.equals(deviceInfo)) {
                if (expireDate.getTime() > System.currentTimeMillis()) {
                    if (token.equals(userLogin.getOwnToken())){//校验成功,放行
                        return true;
                    }
                }
            }
            out.append(JSON.toJSONString(new ResponseResult("error", "token验证不通过", null)));
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            response.sendError(500);
            return false;
        }

如有错误,请及时指出,感谢大家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值