1-(2)、服务鉴权JWT使用

1、 JWT工具类编写

(1)common工程引入依赖(考虑到工具类的通用性)
   
   
       io.jsonwebtoken
       jjwt
       0.9.0
   
(2)修改common工程,创建util.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 java.util.Date;

@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)           //用户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();
    }
}
(3)修改user工程的application.yml, 添加配置
#jwt相关
jwt:
  config:
    key: justIT
    ttl: 3600000

2、管理员登陆后台签发token

(1)配置bean,修改user工程Application类
    @Bean
    public JwtUtil jwtUtil(){
        return new JwtUtil();
    }
(2)修改AdminController的login方法
    @Autowired
    private JwtUtil jwtUtil;
    
    /**
     * @Description: //TODO 用户登录
     * @Param: []
     * @return: entity.Result
     */
    @PostMapping("/login")
    public Result login(@RequestBody Admin admin){
        admin = adminService.login(admin);
        if (admin == null){
            return new Result(false, StatusCode.LOGINERROR, "登录失败");
        }
        //使得前后端通话
        //生成令牌
        Map map = new HashMap<>();
        String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
        map.put("roles", "admin");
        map.put("token", token);
        return new Result(true, StatusCode.OK, "登录成功", map);
    }
    

测试运行结果:

{
  "flag": true,   
  "code": 20000,   
  "message": "登陆成功",   
  "data": {     
            "token":  "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5ODQzMjc1MDc4ODI5MzgzNjgiLCJzdWIiOiJ4aWFvbWkiLCJpYXQiOjE1MjM1MjQxNTksInJvbGVzIjoiYWRtaW4iLCJleHAiOjE1MjM1MjQ1MTl9._YF3oftRNTbq9WCD8Jg1tqcez3cSWoQiDIxMuPmp73o",    
            "name":"admin"   
          } 
}

3、删除用户功能鉴权

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

(1)修改UserServer的deleteById方法 ,判断请求中的头信息,提取token并验证权限。
    @Autowired
    private HttpServletRequest request;
    
    /**
     * 删除,必须有admin角色
     * @param id
     */
    public void deleteById(String id) {
        //获取请求头
        String header = request.getHeader("Authorization");
        if(header == null && !header.startsWith("Bearer ")){//没有头信息,且没按规定的格式开头
            throw new RuntimeException("权限不足");
        }
        //得到token
        String token = header.substring(7);
         //对令牌进行验证
        try {
            Claims claims = jwtUtil.parseJWT(token);
            //如果是管理员
            if (claims == null && !"admin".equals(claims.get("roles"))){
                throw new RuntimeException("权限不足");
            }
        }catch (Exception e){
            throw new RuntimeException("令牌不正确");
        }
        userDao.deleteById(id);
    }

4、使用拦截器方式实现token鉴权

   每个方法都去写一段代码,冗余度太高,不利于维护,那如何做使我们的代码看起来更清爽呢?我们可以将这段代码放入拦截器去实现。

4.1、添加拦截器

   Spring为我们提供了 import org.springframework.web.servlet.HandlerInterceptor 这个适配器, 实现此类,可以非常方便的实现自己的拦截器。他有三个方法:
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲 染)、返回处理(已经渲染了页面)

  • 在preHandle中,可以进行编码、安全控制等处理;
  • 在postHandle中,有机会修改ModelAndView;
  • 在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
(1)创建拦截器类。创建 com.springboot.user.interceptor.JwtInterceptor
/**
 * 拦截器
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler) throws Exception {
        System.out.println("经过了拦截器");
        return true;
    }

(2)配置拦截器类,创建com.Springboot.user.config.InterceptorConfig
/**
 *  拦截器配置类
 */
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {

    @Autowired
    private JwtInterceptor jwtInterceptor;

    protected void addInterceptors(InterceptorRegistry registry) {
        //注册拦截器要声明拦截的对象和拦截的路径
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/**/login/**");
    }
}

4.2 拦截器验证token

(1)修改拦截器类 JwtInterceptor
/**
 *拦截器
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler) throws Exception {
        System.out.println("经过了拦截器");
        //无论如何都放行,具体能不能操作还是在具体的操作中判断;
        //拦截器只是负责把请求头中有token的令牌进行解析验证;
        String header = request.getHeader("Authorization");
        if(header != null && header.startsWith("Bearer ")){//有头信息,且按规定的格式开头
            //得到token
            String token = header.substring(7);
            //对令牌进行验证
            try {
                Claims claims = jwtUtil.parseJWT(token);
                //如果是管理员
                if (claims != null && "admin".equals(claims.get("roles"))){
                    request.setAttribute("claims_admin", claims);
                }
                //如果是普通用户
                if (claims != null && "user".equals(claims.get("roles"))){
                    request.setAttribute("claims_user", claims);
                }
            }catch (Exception e){
                throw new RuntimeException("令牌不正确");
            }
        }
        return true;
    }
}

(2)修改UserService的deleteById方法
    /**
     * 删除,必须有admin角色
     * @param id
     */
    public void deleteById(String id) {
        Claims claims = (Claims) request.getAttribute("claims_admin");
        if (claims == null){
            throw new RuntimeException("权限不足");
        }
        userDao.deleteById(id);
    }

5、发布信息验证Token

步骤:用户登陆签发JWT -------> 携带 token 进行相应的权限操作

你可能感兴趣的:(1-(2)、服务鉴权JWT使用)