zoukankan      html  css  js  c++  java
  • 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");
                }
            }
        }
    }
  • 相关阅读:
    魅族--魅蓝metal
    小米2015.11.24 雷军:我所有的向往
    微软2015.10.4发布会
    创意app1
    奇怪的想法2
    奇怪想法1
    对不起,我爱你(悲剧,慎入)
    聊聊台式机1
    聊聊笔记本1--人生第一台笔记本
    聊聊路由器1
  • 原文地址:https://www.cnblogs.com/jikeyi/p/13357836.html
Copyright © 2011-2022 走看看