jwt的简单使用

简单做一点记录,写得比较乱
优点:无状态(不用存储)、跨域(估计可以放在地址栏)、比redis快(直接当场解析)
缺点: 在颁发后无法让JWT即刻失效。例如改密码之类的操作,无法强制让该用户所有登录态失效。所以对于一些重要的接口,应该进行二次认证,用黑名单解决。
流程总结:
每次一登录成功,立刻用工具类生成令牌返回给前端(一般会把用户的一些信息作为原料制作令牌),前端需要访问受保护的页面时带令牌过来(可以在请求头、请求行、cookie中),用拦截器预先解析令牌得到claim对象,就用这个对象完成权限认证


 
 
代码
判断登陆是否成功是手动的比对密码,登陆成功就获得令牌。以后想保护那个路径,就在那个路径下面获取令牌,并且手动比对,正确后才能继续操作,否则就返回“没有权限”,这样就实现了手动保护。
/**
* 登陆
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(@RequestBody Map<String, String> userMap) {
    Admin admin = adminService.login(userMap);
    if (admin == null) {
        return new Result(false, StatusCode.LOGINERROR, "登录失败");
    }
    //登陆成功之后生成令牌,这里的admin最好是把查出来的用户的实际角色传过去,不要写死
    String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
    Map<String,Object> map = new HashMap<>();
    map.put("admin",admin);
    map.put("token",token);
    return new Result(true, StatusCode.OK, "登录成功", map);
}
手动验证密码,保持存取一致就行了
/**
* 管理员登录
* @param userMap
* @return
*/
public Admin login(Map<String, String> userMap) {
 
 
    String loginname = userMap.get("loginname");
    String password = userMap.get("password");
    if(StringUtils.isEmpty(loginname)||StringUtils.isEmpty(password)){
        return null;
    }
    //根据手机号码查询用户对象
   Admin admin= adminDao.findByLoginname(loginname);
    if(admin == null){
        return null;
    }
    //CharSequence rawPassword:用户登录页面输入的密码   String encodedPassword数据库中查询出来加密的密码
    if(encoder.matches(password,admin.getPassword())){
        return admin;
    }
    return null;
}
生成令牌,工具类的完整代码放在最后面
/**
* 生成JWT
*生成令牌需要加点素材,加多少其实并没有具体的规定,一般加点用户信息和当前时间就行,这样还原的时候顺便能得到用户信息,
* 有了这些素材就能生成加密的字符串了,一定要加盐保证安全性
*
* @param id 当前登录用户的id
* @param subject 登录用户名
* @param roles admin user 角色
*
*/
public String createJWT(String id, String subject, String roles) {
    long nowMillis = System.currentTimeMillis();
    Date now = new Date(nowMillis);
    JwtBuilder builder = Jwts.builder().setId(id)
            .setSubject(subject)
            .setIssuedAt(now)
            //注意,这里的claim相当于自定义键值对
            .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
    if (ttl > 0) {
        //设置过期时间,也可以不设置。注意,如果解析时过期了会报错,最好try起来
        builder.setExpiration( new Date( nowMillis + ttl));
    }
    return builder.compact();
}
用户得到令牌后,在访问重点路径的时候,让前端带过来
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Result delete(@PathVariable String id) {
    //这里用了拦截器,在拦截器那里已经解析好了,这里直接得到claims
    Claims claims = (Claims)request.getAttribute("admin_claims");
    if(claims == null || !claims.get("roles").equals("admin")){
        return new Result(false, StatusCode.ACCESSERROR, "权限不足");
    }
    /*//先验证请求头中token信息 key:Authorization    value:Bearer+空格+token
    String headToken = request.getHeader("Authorization");//请求头token key定义格式 格式校验
    if(StringUtils.isEmpty(headToken) || !headToken.startsWith("Bearer ")){
        return new Result(false, StatusCode.ACCESSERROR, "权限不足");
    }
    //截取head中token
    String realToken = headToken.substring(7);
    //验证失败 返回权限不足
    Claims claims = jwtUtil.parseJWT(realToken);
    if(claims == null || !claims.get("roles").equals("admin")){
        return new Result(false, StatusCode.ACCESSERROR, "权限不足");
    }*/
    //验证通过,则执行删除用户
    userService.deleteById(id);
    return new Result(true, StatusCode.OK, "删除成功");
}
工具类完整代码,使用JWT需要导入jar包
/**
* jwt工具类
* 认证创建token createJWT
* 鉴权解析token parseJWT
* jwt
*   config
*      key :itcast
*      ttl 60*60*1000 = 3600000
*/
@ConfigurationProperties("jwt.config")  //@Value
public class JwtUtil {
 
 
    /**
     * 秘钥,相当于盐,从配置文件中读取
     */
    private String key ;
 
 
    /**
     * 过期时间,从配置文件中读取
     */
    private long ttl ;//一个小时
 
 
    public String getKey() {
        return key;
    }
 
 
    public void setKey(String key) {
        this.key = key;
    }
 
 
    public long getTtl() {
        return ttl;
    }
 
 
    public void setTtl(long ttl) {
        this.ttl = ttl;
    }
 
 
    /**
     * 生成JWT
         *
     * @param id 当前登录用户的id
     * @param subject 登录用户名
     * @param roles admin user 角色
     *
     */
    public String createJWT(String id, String subject, String roles) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder().setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                //注意,这里的claim相当于自定义键值对
                .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
        if (ttl > 0) {
            //设置过期时间,也可以不设置。注意,如果解析时过期了会报错,最好try起来
            builder.setExpiration( new Date( nowMillis + ttl));
        }
        return builder.compact();
    }
 
 
    /**
     * 解析JWT,如果过期了会报错,最好try起来
     * 解析出来的Claims对象它的结构跟上面加密的一样,里面有很多键值对,需要的话
     * 可以取出来
     *
     * @param jwtStr
     * @return
     */
    public Claims parseJWT(String jwtStr){
        return  Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtStr)
                .getBody();
    }
 
 
}
 
posted @ 2020-10-05 13:02  codeDirectory  阅读(473)  评论(0)    收藏  举报