token解决前后端分离认证和跨域问题和JWT的使用

二、使用token解决前端后端分离用户认证问题

2.1 用户提交帐号和密码到服务器的认证接口

  • login.html

  • doSubmit:function(){
        console.log("~~~~~~~~~~~~~doSubmit");
        axios.get("http://localhost:8080/user/login",{
            params:{
                username:this.username,
                password:this.password
            }
        }).then(function(res){
            if(res.data.code==0){
                var token = res.data.data;
                //在前端存储token
                document.cookie = "token="+token;
                //localStorage.setItem("token",token);
                //跳转到index.html
                location.href = "index.html";
            }else{
                //弹出提示框:提示登录失败
            }
        });
    }

    2.2 认证接口

    • --> 接受帐号和密码进行认证

    • --> 生成token(如果是随机token则需要在服务器进行存储,如果是按照特定的协议生成则无需存储)

    • --> 将生成的token响应给前端

  • UserController
    • @RequestMapping(value = "/login",method = RequestMethod.GET)
      @ApiOperation(value = "用户认证接口",notes = "调用此接口的注意事项")
      @ApiImplicitParams({
          @ApiImplicitParam(paramType = "query",name="username", required = true,dataType = "Book"),
          @ApiImplicitParam(paramType = "query",name="password",required = true,dataType = "String")
      })
      public ResultVO login(String username, String password, HttpServletRequest request) {
          try {
              User user  = userService.checkLogin(username, password);
              if (user!=null){
                  //登录成功
                  //request.getSession().setAttribute("user",user);
                  //b.生成token(自定义生成规则)
                  String token = TokenUtil.createToken(username);
                  //c.将token回传给前端
                  return new ResultVO(0,"success",token);
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
          return new ResultVO(1,"fail");
      }
      public class TokenUtil {
      
          public static String createToken(String username){
              String f = username.substring(0,1);
              String l = username.substring(username.length()-1);
              String str = l+f+username+l+f;
              String token = username+"."+Base64.encode(str.getBytes());
              return token;
          }
      
      }

2.3 前端获取并存储token(cookie,localstorage)

  • 在登录页面的回调函数中

  • if(res.data.code==0){
        var token = res.data.data;
        //在前端存储token
        document.cookie = "token="+token;
        //localStorage.setItem("token",token);
        //跳转到index.html
        location.href = "index.html";
    }else{
        //弹出提示框:提示登录失败
    }

2.4 当前端再次请求服务器接口时必须携带token

  • 当再次请求接口时,需要携带token

  • //【获取token】
    //1.从cookie获取
    var cks = document.cookie.split(",");
    for(var i=0; i<cks.length; i++){
        if(cks[i].split("=")[0] == "token"){
            this.token = cks[i].split("=")[1];
        }
    }
    
    //2.从localStorage获取
    this.token = localStorage.getItem("token");
    
    
    //【axios发送请求,header携带token】
    //1.设置axios的请求header中常驻token
    axios.defaults.headers.common["token"] = this.token;
    
    //2.在每次请求时设置token
    axios({
        url:"",
        method:"",
        params:{},
        data:{},
        headers:{
            token:this.token
        }
    }).then(res=>{
        //处理响应结果
    });

2.5 在服务器通过拦截器验证token

  • 创建自定义异常类处理token不合法异常

  • public class UnTokenException extends Exception {
        public UnTokenException(String message) {
            super(message);
        }
    }
  • 创建拦截器
  • @Component
    public class LoginInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if("options".equalsIgnoreCase(request.getMethod())){
                return true;
            }else {
                String token = request.getHeader("token");
                System.out.println(token);
                if (token != null && !"".equals(token)) {
                    //验证token
                    String username = token.split("[.]")[0];
                    String rightToken = TokenUtil.createToken(username);
                    if (rightToken.equals(token)) {
                        return true;
                    } else {
                        //抛出自定义异常,通过全局异常处理返回给前端一个VO(包含“请先登录”提示信息)
                        throw new UnTokenException("非法token,请认证");
                    }
                } else {
                    throw new UnTokenException("请求参数不正确(缺少token)");
                }
            }
        }
    }
  • 配置拦截器

  • @Configuration
    public class AppConfig implements WebMvcConfigurer {
    
        @Resource
        private LoginInterceptor loginInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(loginInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns("/user/**");
        }
    
    }
  • 通过全局异常处理,处理token不合法问题
  • @ControllerAdvice
    @CrossOrigin
    public class UnTokenExceptionHanlder {
    
        @ExceptionHandler
        @ResponseBody
        public ResultVO exceptionHanlder(Exception e){
            return new ResultVO(1,e.getMessage());
        }
    
    }

三、服务器跨域设置

  • 跨域配置

  • @Configuration
    public class CrossConfig {
        @Bean
        public WebMvcConfigurer getWebMvcConfigurer() {
            WebMvcConfigurer webMvcConfigurer = new WebMvcConfigurer() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                            .allowedOrigins("*")
                            .allowedHeaders("*")
                            .allowedMethods("*")
                            .allowCredentials(false);
                }
            };
            return webMvcConfigurer;
        }
    
    }
    • 在控制器(接口)添加@CrossOrigin

    • 拦截放行预检

    • @Component
      public class LoginInterceptor implements HandlerInterceptor {
      
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
              if("options".equalsIgnoreCase(request.getMethod())){
                  return true;
              }else {
                  String token = request.getHeader("token");
                  System.out.println(token);
                  if (token != null && !"".equals(token)) {
                      //验证token
                      String username = token.split("[.]")[0];
                      String rightToken = TokenUtil.createToken(username);
                      if (rightToken.equals(token)) {
                          return true;
                      } else {
                          //抛出自定义异常,通过全局异常处理返回给前端一个VO(包含“请先登录”提示信息)
                          throw new UnTokenException("非法token,请认证");
                      }
                  } else {
                      throw new UnTokenException("请求参数不正确(缺少token)");
                  }
              }
          }
      }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4.1在项目中导入JWT依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.8.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

4.2 生成Token

String token = Jwts.builder()
    .setSubject(user.getUsername())     //设置用户信息
    .setId(user.getId()+"")             //设置用户ID
    .setIssuedAt(new Date())            //设置token的创建时间
    .setExpiration(new Date(System.currentTimeMillis()+60*1000))  //设置过期时间
    .signWith(SignatureAlgorithm.HS256,"qianfeng")  //加密方式及key
    .compact();

4.3 拦截器校验token

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws UnTokenException, ExpiredJwtException,SignatureException {
        if("options".equalsIgnoreCase(request.getMethod())){
            return true;
        }else {
            String token = request.getHeader("token");
            System.out.println(token);
            if (token != null && !"".equals(token)) {
                //校验token
                JwtParser parser = Jwts.parser();
                parser.setSigningKey("qianfeng");

                //解析token,只要不抛出异常表示token正常
                Jws<Claims> claimsJws = parser.parseClaimsJws(token);
                //从token中获取信息
                Claims body = claimsJws.getBody();
                String subject = body.getSubject();
                return true;
            } else {
                throw  new UnTokenException("token为NULL");
            }
        }
    }
}
原文地址:https://www.cnblogs.com/jikeyi/p/13357836.html