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");
            }
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM