JWT鉴权的实现

1 JWT 工具类

1.1 引入依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

1.2 创建 JwtUtil

package util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * Created by Administrator on 2018/4/11.
 */
@ConfigurationProperties("jwt.config")
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
     * @param subject
     * @return
     */
    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)
                .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
        if (ttl > 0) {
            builder.setExpiration( new Date( nowMillis + ttl));
        }
        return builder.compact();
    }

    /**
     * 解析JWT
     * @param jwtStr
     * @return
     */
    public Claims parseJWT(String jwtStr){
        return  Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtStr)
                .getBody();
    }

}

思路:

  1. JWT 工具类,无非两个内容:生成 JWT、解析 JWT。
  2. 生成 JWT 的方法,需要 id、主题 subject、发布此 JWT 的时间(保证 JWT 不重复)、签证(传入签名算法和盐 key);由于本实例做的是不同用户的鉴权问题,这里指定 admin 用户才有权限签发 token,于是我们自定义一个 claim ;并且还需要设置一个过期时间,它最好体现在配置文件中,于是我们多创建一个变量 ttl(time to live)。
  3. 由于我们需要的 JWT 是一个字符串,用 compact() 方法生成就行。
  4. 解析 JWT 的方法,先用 parser() 方法,然后传入盐和 JWT 字符串,最后 getBody()

1.3 properties.yml 配置文件

在配置文件中写入盐 key 和 过期时间 ttl。

jwt:
	config:
		key: helloWorld
		ttl: 360000

2 签发 token

2.1 注入 JwtUtil 到容器

@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

    @Bean
    public IdWorker idWorker() {
        return new IdWorker(1, 1);
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtUtil jwtUtil() {
        return new JwtUtil();
    }
}

2.2 生成 token

调用 JWT 工具类,传入 id、登录名、角色,然后存在一个 map 中返回给前端。

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping(value = "/login")
    public Result login(@RequestBody Admin admin) {
        Admin adminLogin = adminService.login(admin);
        if (adminLogin == null) {
            return new Result(StatusCode.ERROR, false, "登录失败");
        }
        // 使得前后端可以通话的操作,采用JWT来实现
        // 生成令牌
        String token = jwtUtil.createJWT(adminLogin.getId(), adminLogin.getLoginname(), "admin");
        Map<String , Object> map = new HashMap<>();
        map.put("token", token);
        map.put("role", "admin");
        return new Result(StatusCode.OK, true, "登录成功", map);
    }

2.3 结果

可以从前端看到我们生成的 token 了。
在这里插入图片描述

3 解析 token

需求:删除用户,必须拥有管理员权限,否则不能删除。
前后端约定:前端请求微服务时需要添加头信息 Authorization,内容为 Bearer+空格+token

3.1 判断请求头

修改 UserService 的 deleteUserById 方法 ,判断请求中的头信息,提取 token 并验证权限。

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    HttpServletRequest request;

    public void deleteUserById(String userId) {
        String header = request.getHeader("Authorization");
        if (header == null || "".equals(header)) {
            throw new RuntimeException("没有Authorization请求头");
        }
        if (!header.startsWith("Bearer")) {
            throw new RuntimeException("Authorization非标准格式");
        }
        String token = header.substring(7);
        try {
            Claims claims = jwtUtil.parseJWT(token);
            String roles = (String) claims.get("roles");
            if (null == roles || !roles.equals("admin")) {
                throw new RuntimeException("用户角色错误");
            }
        } catch (Exception e) {
            throw new RuntimeException("token错误");
        }

        userDao.deleteById(userId);
    }

3.2 测试

原本的数据库用的 user 表内容:
在这里插入图片描述

(1)没有加 header 的时候:
在这里插入图片描述
(2)Authorization 不是按照格式来的时候:
在这里插入图片描述
(3)token 格式错误的时候:
在这里插入图片描述
(4)填入正确 token 的时候:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值