基于JWT的API鉴权如何实现?

    科技2022-07-15  95

    前言

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

    1. Spring中的拦截器

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

    1.在preHandle中,可以进行编码、安全控制等处理; 2.在postHandle中,有机会修改ModelAndView; 3.在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。

    2. 拦截器中鉴权

    (1)修改签发token的登录服务添加API权限

    @RequestMapping(value="/login",method = RequestMethod.POST) 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); } }

    (2)添加拦截器 JwtInterceptor

    ** * 自定义拦截器 * 继承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(RequestMapping.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); } }

    (3)修改BaseController

    public class BaseController { protected HttpServletRequest request; protected HttpServletResponse response; protected String companyId; protected String companyName; protected Claims claims; @ModelAttribute public void setResAnReq(HttpServletRequest request,HttpServletResponse response) { this.request = request; this.response = response; Object obj = request.getAttribute("user_claims"); if(obj != null) { this.claims = (Claims) obj; this.companyId = (String)claims.get("companyId"); this.companyName = (String)claims.get("companyName"); } } }

    (4)修改UserController的profile方法

    @RequestMapping(value="/profile",method = RequestMethod.POST) public Result profile(HttpServletRequest request) throws Exception { String userid = claims.getId(); //获取用户信息 User user = userService.findById(userid); //根据不同的用户级别获取用户权限 ProfileResult result = null; if("user".equals(user.getLevel())) { result = new ProfileResult(user); }else { Map map = new HashMap(); if("coAdmin".equals(user.getLevel())) { map.put("enVisible","1"); } List<Permission> list = permissionService.findAll(map); result = new ProfileResult(user,list); } return new Result(ResultCode.SUCCESS,result); }

    (5)配置拦截器类,创建com.ihrm.system.SystemConfig

    // implements WebMvcConfiguer @Configuration public class SystemConfig extends WebMvcConfigurationSupport { @Autowired private JwtInterceptor jwtInterceptor; /** * 添加拦截器的配置 */ @Override protected void addInterceptors(InterceptorRegistry registry) { //1.添加自定义拦截器 registry.addInterceptor(jwtInterceptor). addPathPatterns("/**").//2.指定拦截器的url地址 excludePathPatterns("/sys/login","/frame/register/**");//3.指定不拦截的url地址 } }

    (6)在启动类中加入

    //解决 jpa 的 no session @Bean public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() { return new OpenEntityManagerInViewFilter(); }

    是不是一脸懵,再看回这个视频

    Processed: 0.017, SQL: 8