国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

解決前后端分離Vue項目部署到服務(wù)器后出現(xiàn)的302重定向問題

這篇具有很好參考價值的文章主要介紹了解決前后端分離Vue項目部署到服務(wù)器后出現(xiàn)的302重定向問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

問題描述

最近發(fā)現(xiàn)自己開發(fā)的vue前后端分離項目因為使用了spring security 安全框架,即使在登錄認證成功之后再調(diào)用一些正常的接口總是會莫名奇妙地出現(xiàn)302重定向的問題,導致接口數(shù)據(jù)出不來。奇怪的是這個問題在本地開發(fā)環(huán)境并沒有,而是部署到了服務(wù)器之后才會有。
前后端分離后端重定向怎么辦,springboot項目實戰(zhàn),Vue,vue.js,服務(wù)器,前端
接口無法加載響應(yīng)數(shù)據(jù)

接口重定向標識Location顯示需要重新登錄認證,而且這個請求還是GET請求
前后端分離后端重定向怎么辦,springboot項目實戰(zhàn),Vue,vue.js,服務(wù)器,前端

問題原因定位

出現(xiàn)這個問題很顯然是當前用戶在Spring Security中丟失了認證信息,奇怪的是本地開發(fā)環(huán)境并不會出現(xiàn)這種問題,原因是我本地開發(fā)環(huán)境的前端用的是Vite啟動的前端服務(wù),而部署到服務(wù)器時卻是Nginx起的前端服務(wù)。而筆者在Spring Security的配置類中注冊了一個用于Jwt token認證的過濾器JwtAuthenticationFilterBean, 并注冊在UsernamePasswordAuthenticationFilter之前。通過jwt token認證相當于spring security需要對用戶的每次請求都先認證一次,如果用戶的認證信息沒有保存到SecurityContext類中的authentication中就會在調(diào)用非登錄接口獲取數(shù)據(jù)時出現(xiàn)這種重定向到登錄頁面的問題。

自定義的Jwt token認證類源碼如下:

JwtAuthenticationFilterBean

 private final static Logger logger =             LoggerFactory.getLogger(JwtAuthenticationFilterBean.class);

    private String AUTHORIZATION_NAME = "Authorization";

    // private String BEARER = "Bearer";

    private static List<String> whiteRequestList = new ArrayList<>();

    static {
        whiteRequestList.add("/bonus/member/checkSafetyCode");
        whiteRequestList.add("/bonus/login");
        whiteRequestList.add("/bonus/member/login");
        whiteRequestList.add("/bonus/common/kaptcha");
        whiteRequestList.add("/bonus/admin/login");
        whiteRequestList.add("/bonus/favicon.ico");
        whiteRequestList.add("/bonus/doc.html");
        whiteRequestList.add("/bonus/error");
    }
@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        logger.info("requestUrl="+request.getRequestURI());
        if(HttpMethod.OPTIONS.name().equals(request.getMethod())){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        if(whiteRequestList.contains(request.getRequestURI()) || (request.getRequestURI().contains("admin/dist") &&
                request.getRequestURI().endsWith(".css") || request.getRequestURI().equals(".js") ||
                request.getRequestURI().endsWith(".png") || request.getRequestURI().endsWith("favicon.ico"))){
            // 如果是登錄和安全碼驗證請求直接放行
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        } else {
               Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
               if(authentication!=null && authentication.getPrincipal()!=null){
                   MemInfoDTO memInfoDTO = (MemInfoDTO) authentication.getPrincipal();
                   logger.info("memInfoDTO={}", JSONObject.toJSONString(memInfoDTO));
                   filterChain.doFilter(servletRequest, servletResponse);
                   return;
               }
               String authToken = request.getHeader(AUTHORIZATION_NAME);
               if(StringUtils.isEmpty(authToken)){
                   String message = "http header Authorization is null, user Unauthorized";
                   response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                   response.setStatus(HttpStatus.UNAUTHORIZED.value());
                   this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
                   return;
               } else {
                   try {
                       DecodedJWT decodedJWT = JWT.decode(authToken);
                       Map<String, Claim> claimMap = decodedJWT.getClaims();
                       Claim expireClaim = claimMap.get("exp");
                       Date expireDate = expireClaim.asDate();
                       // 校驗token 是否過期
                       if(expireDate.before(DateUtil.date(System.currentTimeMillis()))){
                           String message = "Authorization token expired";
                           this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
                           return;
                       }
                       Claim memAccountClaim = claimMap.get("memAccount");
                       if(memAccountClaim==null || StringUtils.isEmpty(memAccountClaim.asString())){
                           String message = "memAccount cannot be null";
                           response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                           response.setStatus(HttpStatus.UNAUTHORIZED.value());
                           this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
                           return;
                       }
                       filterChain.doFilter(servletRequest, servletResponse);
                   } catch (JWTDecodeException e) {
                       String message = "JWT decode authToken failed, caused by " + e.getMessage();
                       this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
                       return;
                   }
               }
        }

    }

上面的whiteRequestList中的元素為白名單請求,對于白名單請求Spring Security不進行攔截,直接放行。對于白名單中的請求部署到服務(wù)器后是不會有這種302重定向到登錄頁面的問題。因為這些白名單請求在Spring Security中也進行了放行, 源碼如下。

SecurityConfig#configure(HttpSecurity)方法源碼:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtAuthenticationFilterBean jwtAuthenticationFilterBean = new JwtAuthenticationFilterBean();
        // http過濾器鏈中注冊jwt token 認證過濾器
        http.addFilterBefore(jwtAuthenticationFilterBean, UsernamePasswordAuthenticationFilter.class);
        // 配置跨域
        http.cors().configurationSource(corsConfigurationSource())
                .and().logout().invalidateHttpSession(true).logoutUrl("/member/logout").permitAll()
        ;
        http.authorizeRequests()
                // 放行白名單請求
                .antMatchers("/member/checkSafetyCode").permitAll()
                .antMatchers("/doc.html").permitAll()
                .antMatchers("/common/kaptcha").permitAll()
                .antMatchers("/admin/login").permitAll()
                .anyRequest().authenticated()
                .and().httpBasic()
                // 表單登錄認證
                .and().formLogin()
                .loginPage(loginPageUrl)
                // 自定用戶登錄處理接口
                .loginProcessingUrl("/member/login")
                .successHandler((httpServletRequest, httpServletResponse, authentication) -> {              // httpServletResponse參數(shù)中返回用戶信息和jwt token給客戶端
httpServletResponse.setContentType("application/json;charset=utf-8");
                     httpServletResponse.setStatus(HttpStatus.OK.value());
                     PrintWriter printWriter = httpServletResponse.getWriter();
                     // 從認證信息中獲取用戶信息
                     MemInfoDTO memInfoDTO = (MemInfoDTO) authentication.getPrincipal();
                     Map<String, Object> userMap = new HashMap<>();
                     userMap.put("memId", memInfoDTO.getMemId());
                     userMap.put("memAccount", memInfoDTO.getMemAccount());
                     userMap.put("memPwd", memInfoDTO.getMemPwd());
                     BigDecimal totalCredit = memInfoDTO.getTotalCreditAmount()!=null?new BigDecimal(memInfoDTO.getTotalCreditAmount()/100, mathContext): new BigDecimal("0.0");
                     userMap.put("totalCreditAmount", totalCredit);
                     BigDecimal usedCredit = memInfoDTO.getUsedCreditAmount()!=null?new BigDecimal(memInfoDTO.getUsedCreditAmount()/100, mathContext):new BigDecimal("0.0");
                     userMap.put("usedCreditAmount", usedCredit);
                     Long remainCredit = (memInfoDTO.getTotalCreditAmount()==null?0:memInfoDTO.getTotalCreditAmount()) - (memInfoDTO.getUsedCreditAmount()==null?0:memInfoDTO.getUsedCreditAmount());
                     BigDecimal remainCreditAmount = new BigDecimal(remainCredit/100, mathContext);
                     userMap.put("remainCreditAmount", remainCreditAmount);
                     userMap.put("authorities", memInfoDTO.getAuthorities());
                     Map<String, Object> dataMap = new HashMap<>();
                     dataMap.put("memInfo", userMap);
                     dataMap.put("authenticatedToken", JwtTokenUtil.genAuthenticatedToken(userMap)); // 根據(jù)用戶信息生成jwt token
                     ResponseResult<Map<String, Object>> responseResult = ResponseResult.success(dataMap, "login success");
                     printWriter.write(JSONObject.toJSONString(responseResult));
                     printWriter.flush();
                     printWriter.close();
                }).permitAll()
                .and().csrf().disable() // 禁用csrf
            .exceptionHandling() //認證異常處理
            .accessDeniedHandler(accessDeniedHandler());
    }

問題解決方案

有兩種方式解決這個部署到服務(wù)器后產(chǎn)生的302重定向問題

  • 第一種就是在Spring Security的配置類的configure(HttpSecurity)方法中對出現(xiàn)302重定向的請求進行放行,向放行白名單請求一樣進行處理。不過這種方式解決的話相當于棄用了Spring Security安全框架,任意用戶都能訪問后臺接口,應(yīng)用沒有安全可言,不推薦使用;
  • 第二種方式便是在JwtAuthenticationFilterBean#doFilter方法中通過反解jwt token得到訪問用戶的身份信息后,再將其存入SpringSecurityContextHolder類中與當前線程綁定的SecurityContext類變量contextauthentication變量中,源碼如下:
try {
                       DecodedJWT decodedJWT = JWT.decode(authToken);
                       Map<String, Claim> claimMap = decodedJWT.getClaims();
                       Claim expireClaim = claimMap.get("exp");
                       Date expireDate = expireClaim.asDate();
                       // 校驗token 是否過期
                       if(expireDate.before(DateUtil.date(System.currentTimeMillis()))){
                           String message = "Authorization token expired";
                           this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
                           return;
                       }
                       Claim memAccountClaim = claimMap.get("memAccount");
                       if(memAccountClaim==null || StringUtils.isEmpty(memAccountClaim.asString())){
                           String message = "memAccount cannot be null";
                           response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                           response.setStatus(HttpStatus.UNAUTHORIZED.value());
                           this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
                           return;
                       }
                      logger.info("用戶:"+memAccountClaim.asString()+" 調(diào)用請求 "+request.getRequestURI()+" 需要重新獲得認證");
                       // 組裝認證信息
                       MemInfoDTO memInfoDTO = new MemInfoDTO();
                       memInfoDTO.setMemAccount(memAccountClaim.asString());
                       Claim memIdClaim = claimMap.get("memId");
                       memInfoDTO.setMemId(memIdClaim.asLong());
                       Claim memPwdClaim = claimMap.get("memPwd");
                       memInfoDTO.setMemPwd(memPwdClaim.asString());
                       Claim totalCreditClaim = claimMap.get("totalCreditAmount");
                       Double totalCreditAmount = totalCreditClaim.asDouble()*100;
                       String totalCreditAmountStr = String.valueOf(totalCreditAmount);
                       logger.info("totalCreditAmountStr={}", totalCreditAmountStr);
                       if(totalCreditAmountStr.lastIndexOf(".")>-1){
                           memInfoDTO.setTotalCreditAmount(Long.valueOf(totalCreditAmountStr.substring(0, totalCreditAmountStr.lastIndexOf("."))));
                       } else {
                           memInfoDTO.setTotalCreditAmount(Long.valueOf(totalCreditAmountStr));
                       }
                       Claim usedCreditClaim = claimMap.get("usedCreditAmount");
                       Double usedCreditAmount = usedCreditClaim.asDouble()*100;
                       String usedCreditAmountStr = String.valueOf(usedCreditAmount);
                       if(usedCreditAmountStr.lastIndexOf(".")>-1){
                           memInfoDTO.setUsedCreditAmount(Long.valueOf(usedCreditAmountStr.substring(0, usedCreditAmountStr.lastIndexOf("."))));
                       } else {
                           memInfoDTO.setUsedCreditAmount(Long.valueOf(usedCreditAmountStr));
                       }
                       Claim authorityClaim = claimMap.get("authorities");
                       List<String> authorities = authorityClaim.asList(String.class);
                       List<GrantedAuthority> authorityList = new ArrayList<>(authorities.size());
                       for(String authority: authorities){
                           SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority);
                           authorityList.add(grantedAuthority);
                       }
                       memInfoDTO.setAuthorities(authorityList);
                       // 組裝認證對象
                       UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(memInfoDTO, memInfoDTO.getMemPwd(), memInfoDTO.getAuthorities());
                       // 將認證對象放入SecurityContext中
                       SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                       // 請求頭認證通過, 放行請求
                       filterChain.doFilter(servletRequest, servletResponse);

校驗修改效果

修改好源碼后重新打包部署到服務(wù)器(關(guān)于如何打包部署,網(wǎng)上已有很多詳細的指導文章,這里就不贅述了)

部署好應(yīng)用之后登錄之后系統(tǒng)會自動跳轉(zhuǎn)到首頁http://javahsf.club:3000/home

這時候就不會有之前的302重定向問題了,也可以看到頁面的數(shù)據(jù)成功加載出來了

前后端分離后端重定向怎么辦,springboot項目實戰(zhàn),Vue,vue.js,服務(wù)器,前端
通過F12調(diào)試模式查看網(wǎng)絡(luò)請求也可以看到?jīng)]有302重定向的問題了,數(shù)據(jù)也成功返回了
前后端分離后端重定向怎么辦,springboot項目實戰(zhàn),Vue,vue.js,服務(wù)器,前端
為了進一步驗證調(diào)用這個接口時需要重新認證用戶的登錄信息,我們通過在部署目錄執(zhí)行 cat ./logs/spring.log命令可以看到下面這幾行日志信息

2023-01-15 16:22:10.418  INFO 9638 --- [http-nio-0.0.0.0-8090-exec-2] c.b.b.c.JwtAuthenticationFilterBean      : requestUrl=/bonus/openResult/page/data
2023-01-15 16:22:10.509  INFO 9638 --- [http-nio-0.0.0.0-8090-exec-2] c.b.b.c.JwtAuthenticationFilterBean      : 用戶:heshengfu 調(diào)用請求 /bonus/openResult/page/data 需要重新獲得認證

由此驗證了302重定向的問題是接口之前是spring security框架需要重新認證用戶登錄信息卻沒有拿到用戶的認證信息導致的,只需要調(diào)用這個接口驗證jwt token信息,然后解析出用戶身份信息后重新保存到SecurityContextHolder類的SecurityContext類型變量context中的Authentication變量authentication中,問題就得到了解決。

相關(guān)閱讀

【1】Spring Security的項目中集成JWT Token令牌安全訪問后臺API
需要本文源碼的朋友可通過筆者發(fā)布在個人微信公眾號上的這篇在文末的獲取項目源碼的方式獲取

寫在最后

本文首發(fā)個人微信公眾號【阿福談Web編程】,歡迎喜歡我的文章的讀者朋友們加個關(guān)注,大家一起交流學習,謝謝。
文章來源地址http://www.zghlxwxcb.cn/news/detail-648159.html

到了這里,關(guān)于解決前后端分離Vue項目部署到服務(wù)器后出現(xiàn)的302重定向問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 服務(wù)器部署前后端分離項目

    服務(wù)器部署前后端分離項目

    做了一個前后端分離的項目來熟悉開發(fā)的整個流程,我把整個流程記錄下來了,用作以后的參考。 安裝jdk 1、在/usr/local目錄下創(chuàng)建jdk文件夾,并將jdk安裝包放到/usr/local/jdk包下并解壓 1.1通過文件傳輸工具將jdk包上傳到服務(wù)器上 1.2輸入解壓命令 1.3解壓完成,生成下面的文件

    2023年04月22日
    瀏覽(24)
  • 前后端分離項目部署到服務(wù)器

    前后端分離項目部署到服務(wù)器

    目錄 一、準備服務(wù)器 1.1 服務(wù)器的購買 1.2 服務(wù)器的配置 1.3 nginx配置文件的編寫 二、前端項目打包及部署 三、后端項目打包及部署 服務(wù)器購買可以在國內(nèi)選擇阿里云、騰訊云、百度云等等,至于國外服務(wù)器自行探索。 注:服務(wù)器在國內(nèi)的網(wǎng)站需要進行ICP備案操作,服務(wù)器在

    2024年01月24日
    瀏覽(28)
  • 前后端分離項目的服務(wù)器部署

    前后端分離項目的服務(wù)器部署

    系統(tǒng)環(huán)境簡介: 本地操作系統(tǒng):Mac OS Monterey 12.3.1 阿里云服務(wù)器:CentOS 7.8 后端開發(fā)工具:IntelliJ IDEA 前端開發(fā)工具:WebStorm 項目部署的前提條件: ① 需要購買一個域名,并且完成備案 ② 需要擁有一臺公網(wǎng)服務(wù)器,以阿里云服務(wù)器為例 ③ 需要熟練掌握 Linux 操作系統(tǒng)的使用

    2024年02月04日
    瀏覽(94)
  • SpringBoot前后端分離項目,打包、部署到服務(wù)器詳細圖文流程

    SpringBoot前后端分離項目,打包、部署到服務(wù)器詳細圖文流程

    1.修改MySQL配置 修改MySQL地址,修改需要部署的數(shù)據(jù)名,賬號和密碼 2.修改Redis配置 修改Redis地址,修改需要部署的Redis密碼(如果需要的話) 3.修改日志路徑和字符集配置 修改logback.xml中日志的保存地址 重新設(shè)置日志字符集(防止放到服務(wù)器上去之后日志出現(xiàn)亂碼) 1.上傳前

    2024年02月13日
    瀏覽(25)
  • 若依springboot+vue前后端分離系統(tǒng)部署到騰訊服務(wù)器教程

    若依springboot+vue前后端分離系統(tǒng)部署到騰訊服務(wù)器教程

    前后端分離的開發(fā)模式在現(xiàn)代web應(yīng)用開發(fā)中越來越流行,它可以提高開發(fā)效率、降低維護成本、提高系統(tǒng)的可擴展性和可維護性。而騰訊云作為國內(nèi)領(lǐng)先的云計算服務(wù)提供商,為開發(fā)者提供了穩(wěn)定、高效、安全的云計算服務(wù),為前后端分離應(yīng)用的部署提供了良好的解決方案。

    2024年02月04日
    瀏覽(31)
  • (一)專題介紹:移動端安卓手機改造成linux服務(wù)器&linux服務(wù)器中安裝軟件、部署前后端分離項目實戰(zhàn)

    總體概述: 本篇文章隸屬于“手機改造服務(wù)器 部署前后端分離項目”系列專欄,該專欄將分多個板塊,每個板塊獨立成篇 來詳細記錄:手機(安卓)改造成個人服務(wù)器(Linux)、Linux中安裝軟件、配置開發(fā)環(huán)境、部署JAVA+VUE+MySQL5.7前后端分離項目,以及內(nèi)網(wǎng)穿透實現(xiàn)外網(wǎng)訪問等全過

    2024年02月04日
    瀏覽(21)
  • SpringBoot+Vue前后端分離項目+云服務(wù)器(nginx配置http/https)

    SpringBoot+Vue前后端分離項目+云服務(wù)器(nginx配置http/https)

    目錄 1.Java項目打包 2.前端項目打包 ok,項目準備好了,接下來就是服務(wù)器方面的操作了 3.服務(wù)器 1.點擊控制臺 2.找到 ECS云服務(wù)器 3.概覽-我的資源 ?4.重置服務(wù)器密碼 ?5.配置安全組 4.域名 1.買域名 2.備案? 3.解析至服務(wù)器 31.控制臺找到 ?3.2.域名列表 ,找到需要的域名,點擊解析?

    2024年02月09日
    瀏覽(19)
  • 在centos服務(wù)器中完成jdk,tomcat,MySQL的安裝以及前后端分離項目中后端的部署

    在centos服務(wù)器中完成jdk,tomcat,MySQL的安裝以及前后端分離項目中后端的部署

    目錄 一. jdk,tomcat的安裝 1.將要安裝的軟件壓縮包放入到centos服務(wù)器上 ?2. 解壓對應(yīng)的安裝包 3. jdk環(huán)境變量配置 4. tomcat啟動 5. 關(guān)閉防火墻 ?二. MySQL安裝 1. 卸載mariadb,否則安裝MySql會出現(xiàn)沖突(先查看后刪除再查看) 2. 將MySQL安裝包解壓到指定目錄 3. 開始安裝,-ivh 其中i表示

    2024年02月06日
    瀏覽(29)
  • 若依(Ruoyi)前后端分離版項目部署到服務(wù)器(Linux環(huán)境)后,刷新頁面報錯:404 Not Found

    若依(Ruoyi)前后端分離版項目部署到服務(wù)器(Linux環(huán)境)后,刷新頁面報錯:404 Not Found

    原文章: 若依(ruoyi)前后端分離版使用教程之若依后端部署阿里云服務(wù)器步驟(超詳細)_藍多多的小倉庫的博客-CSDN博客 問題: ????????在若依項目部署服務(wù)器后,可以正常運行,但如果執(zhí)行刷新頁面操作,便會出現(xiàn)404 Not Found。 原因: ????????Nginx未正確配置。由

    2024年02月17日
    瀏覽(30)
  • ruoyi若依前后端分離項目部署到服務(wù)器后,PUT DELETE請求403錯誤,GET POST請求正常

    后端打包方式war,部署到tomcat8, PUT DELETE請求報403錯誤,網(wǎng)上有三種說法 第一種是跨域請求問題 第二種是服務(wù)器沒有放開了PUT DELETE請求,需要前端添加header ruoyi vue 自動生成代碼PUT DELETE為http不安全方法,這個怎么解決安全問題 · Issue #I43AX6 · 若依/RuoYi-Vue - Gitee.com 用域名訪問

    2024年01月17日
    瀏覽(70)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包