文章目录
jwt格式实现权限校验
项目架构
项目依赖
<!-- jwt工具包 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
主要功能类
JwtUtils
创建解析token工具类
-
创建token方法
//签名私钥 private String key = "laosan123456"; //15分钟过期 1000*60*15 = 900000 private Long ttl = 900000L; public String createJwt(String id, String name, Map<String, Object> map) { //设置失效时间 long now = System.currentTimeMillis();//当前毫秒 long exp = now + ttl; //创建jwtBuilder JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(name) .setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, key); //根据map设置claims,即用户自定义数据 for (Map.Entry<String, Object> entry : map.entrySet()) { jwtBuilder.claim(entry.getKey(), entry.getValue()); } jwtBuilder.setExpiration(new Date(exp)); //创建token String token = jwtBuilder.compact(); return token; }
-
解析token 方法
public Claims parseJwt(String token) { return Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); }
UserController
用户登录接口即token相关功能验证
-
用户登录
/** * 用户登录 */ @PostMapping(value = "/login") public String login(@RequestBody Map<String, String> loginMap) { String username = loginMap.get("username"); String password = loginMap.get("password"); //TODO 数据库校验,成功则返回,此处没有走数据库在,直接判断用户名和密码是否相同 if (!username.equals(password)) { return "用户名密码错误"; } //登录成功设置基本信息 Map<String, Object> map = new HashMap<>(); // 设置用户基本信息 map.put("userId", "123456123465"); map.put("username", "laosan"); // 设置用户可以访问的api权限信息; map.put("apis", "user.detail"); return jwtUtils.createJwt("123", username, map); }
-
用户详情接口
/** * 获取用户基本信息,用于控制前台菜单,按钮的显示 */ @PostMapping(value = "/detail", name = "user.detail") public Object detail(HttpServletRequest request) { //claims从base中获取 String userid = claims.getId(); //TODO 根据userId从数据库中获取用户的角色、权限、菜单、按钮等信息 Map<String, String> result = new HashMap<>(); // TODO 以下数据从数据库中获取, result.put("menus", "app-menu");//菜单 result.put("button", "app-delete"); //按钮 return result; }
JwtInterceptor
jwt拦截器代码继承HandlerInterceptorAdapter类,并重写preHandle方法,用于校验当前用户是否有访问该接口的权限,此处根据PostMapping中name属性做权限判断;
-
具体拦截器代码
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 通过request获取请求token信息 String token = request.getHeader("token"); //判断请求头信息是否为空 if (!StringUtils.isEmpty(token)) { //解析token获取claims Claims claims = null; try { claims = jwtUtils.parseJwt(token); } catch (Exception e) { throw new Exception("token exception"); } if (claims != null) { //通过claims获取到当前用户的可访问API权限字符串 String apis = (String) claims.get("apis"); HandlerMethod handlerMethod = (HandlerMethod) handler; //获取当前请求接口中的name属性 String name = handlerMethod.getMethodAnnotation(RequestMapping.class).name(); //判断当前用户是否具有响应的请求权限 if (apis.contains(name)) { request.setAttribute("claims", claims); return true; } else { throw new Exception("no permission"); } } } throw new Exception("no token"); }
UserConfig
拦截器配置类,继承WebMvcConfigurationSupport,并重写方法addInterceptors;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//添加自定义拦截器
registry.addInterceptor(jwtInterceptor).
addPathPatterns("/**").//指定拦截器的url地址
excludePathPatterns("/user/login");// 指定不拦截的url地址
}
GlobalExceptionHandler
全局捕获异常类,主要助理拦截器代码抛出的异常,以固定格式返回给前台,此处可定义多种异常;
@ExceptionHandler(value = Exception.class)
@ResponseBody
public String error(HttpServletRequest request, HttpServletResponse response, Exception e) {
e.printStackTrace();
return e.getMessage();
}
简单测试
获取token
- 获取token
token异常
-
无token
-
token无效
权限校验
-
无权限:login接口中apis没有该接口对应的权限;
-
有权限:login接口中apis有该接口对应的权限;