简介
上篇文章讲了下基于 JWT 的用户鉴权的实现方式,这篇来说说 API 的校验。在实际情况下我们不应该让每个请求都能轻易访问到比较敏感的接口,比如涉及到用户信息数据的接口。所以我们需要在前端请求访问 API 接口之前,统一对权限进行控制。
一、修改之前的登录接口
- 在用户登录成功之后,获取到他的所有角色的所有权限,封装到 token 中
/**
* 用户登录
* 1.通过service根据mobile查询用户
* 2.比较password
* 3.生成jwt信息
*
*/
@PostMapping(value="/login")
public Result login(@RequestBody Map<String,String> loginMap) {
String mobile = loginMap.get("mobile");
String password = loginMap.get("password");
User user = userService.findByMobile(mobile);
//登录失败
if(user == null || !user.getPassword().equals(password)) {
return new Result(ResultCode.MOBILEORPASSWORDERROR);
}else {
//登录成功
//api权限字符串
StringBuilder sb = new StringBuilder();
//获取到所有的可访问API权限
for (Role role : user.getRoles()) {
for (Permission perm : role.getPermissions()) {
if(perm.getType() == PermissionConstants.PERMISSION_API) {
sb.append(perm.getCode()).append(",");
}
}
}
Map<String,Object> map = new HashMap<>();
map.put("apis",sb.toString());//可访问的api权限字符串
map.put("companyId",user.getCompanyId());
map.put("companyName",user.getCompanyName());
String token = jwtUtils.createJwt(user.getId(), user.getUsername(), map);
return new Result(ResultCode.SUCCESS,token);
}
}
二、修改自定义拦截器
- 修改控制器方法(此处以删除方法举例),注解里添加 name 属性
/**
* 根据id删除
*/
@DeleteMapping(value = "/user/{id}", name = "API-USER-DELETE")
public Result delete(@PathVariable(Value = "id") String id) {
userService.deleteById(id);
return new Result(ResultCode.SUCCESS);
}
- 修改之前的自定义拦截器
/**
* 自定义拦截器
* 继承HandlerInterceptorAdapter
*
* preHandle:进入到控制器方法之前执行的内容
* boolean:
* true:可以继续执行控制器方法
* false:拦截
* posthandler:执行控制器方法之后执行的内容
* afterCompletion:响应结束之前执行的内容
*
* 1.简化获取token数据的代码编写
* 统一的用户权限校验(是否登录)
* 2.判断用户是否具有当前访问接口的权限
*
*/
@Component
public class JwtInterceptor extends HandlerInterceptorAdapter {
/**
* 简化获取token数据的代码编写(判断是否登录)
* 1.通过request获取请求token信息
* 2.从token中解析获取claims
* 3.将claims绑定到request域中
*/
@Autowired
private JwtUtils jwtUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.通过request获取请求token信息
String authorization = request.getHeader("Authorization");
//判断请求头信息是否为空,或者是否已Bearer开头
if(!StringUtils.isEmpty(authorization) && authorization.startsWith("Bearer")) {
//获取token数据
String token = authorization.replace("Bearer ","");
//解析token获取claims
Claims claims = jwtUtils.parseJwt(token);
if(claims != null) {
//通过claims获取到当前用户的可访问API权限字符串
String apis = (String) claims.get("apis"); //例:api-user-delete,api-user-update
//通过handler
HandlerMethod h = (HandlerMethod) handler;
//获取接口上的reqeustmapping注解
RequestMapping annotation = h.getMethodAnnotation(DeleteMapping.class);
//获取当前请求接口中的name属性的值(即当前接口的权限名)
String name = annotation.name();
//判断当前用户是否具有相应的请求权限
if(apis.contains(name)) {
request.setAttribute("user_claims",claims);
return true;
}else {
throw new CommonException(ResultCode.UNAUTHORISE);
}
}
}
throw new CommonException(ResultCode.UNAUTHENTICATED);
}
}