1. 程式人生 > >Spring Security 前後端分離登入,非法請求直接返回 JSON

Spring Security 前後端分離登入,非法請求直接返回 JSON

hello 各位小夥伴,國慶節終於過完啦,鬆哥也回來啦,今天開始咱們繼續發乾貨!

關於 Spring Security,鬆哥之前發過多篇文章和大家聊聊這個安全框架的使用:

  1. 手把手帶你入門 Spring Security!
  2. Spring Security 登入新增驗證碼
  3. SpringSecurity 登入使用 JSON 格式資料
  4. Spring Security 中的角色繼承問題
  5. Spring Security 中使用 JWT!
  6. Spring Security 結合 OAuth2

不過,今天要和小夥伴們聊一聊 Spring Security 中的另外一個問題,那就是在 Spring Security 中未獲認證的請求預設會重定向到登入頁,但是在前後端分離的登入中,這個預設行為則顯得非常不合適,今天我們主要來看看如何實現未獲認證的請求直接返回 JSON ,而不是重定向到登入頁面。

前置知識

這裡關於 Spring Security 的基本用法我就不再贅述了,如果小夥伴們不瞭解,可以參考上面的 6 篇文章。

大家知道,在自定義 Spring Security 配置的時候,有這樣幾個屬性:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .anyRequest().authenticated()
            .formLogin()
            .loginProcessingUrl("/doLogin")
            .loginPage("/login")
            //其他配置
            .permitAll()
            .and()
            .csrf().disable();
}

這裡有兩個比較重要的屬性:

  • loginProcessingUrl:這個表示配置處理登入請求的介面地址,例如你是表單登入,那麼 form 表單中 action 的值就是這裡填的值。
  • loginPage:這個表示登入頁的地址,例如當你訪問一個需要登入後才能訪問的資源時,系統就會自動給你通過重定向跳轉到這個頁面上來。

這種配置在前後端不分的登入中是沒有問題的,在前後端分離的登入中,這種配置就有問題了。我舉個簡單的例子,例如我想訪問 /hello 介面,但是這個介面需要登入之後才能訪問,我現在沒有登入就直接去訪問這個介面了,那麼系統會給我返回 302,讓我去登入頁面,在前後端分離中,我的後端一般是沒有登入頁面的,就是一個提示 JSON,例如下面這樣:

@GetMapping("/login")
public RespBean login() {
    return RespBean.error("尚未登入,請登入!");
}

完整程式碼大家可以參考我的微人事專案。

也就是說,當我沒有登入直接去訪問 /hello 這個介面的時候,我會看到上面這段 JSON 字串。在前後端分離開發中,這個看起來沒問題(後端不再做頁面跳轉,無論發生什麼都是返回 JSON)。但是問題就出在這裡,系統預設的跳轉是一個重定向,就是說當你訪問 /hello 的時候,服務端會給瀏覽器返回 302,同時響應頭中有一個 Location 欄位,它的值為 http://localhost:8081/login ,也就是告訴瀏覽器你去訪問 http://localhost:8081/login 地址吧。瀏覽器收到指令之後,就會直接去訪問 http://localhost:8081/login 地址,如果此時是開發環境並且請求還是 Ajax 請求,就會發生跨域。因為前後端分離開發中,前端我們一般在 NodeJS 上啟動,然後前端的所有請求通過 NodeJS 做請求轉發,現在服務端直接把請求地址告訴瀏覽器了,瀏覽器就會直接去訪問 http://localhost:8081/login 了,而不會做請求轉發了,因此就發生了跨域問題。

解決方案

很明顯,上面的問題我們不能用跨域的思路來解決,雖然這種方式看起來也能解決問題,但不是最佳方案。

如果我們的 Spring Security 在使用者未獲認證的時候去請求一個需要認證後才能請求的資料,此時不給使用者重定向,而是直接就返回一個 JSON,告訴使用者這個請求需要認證之後才能發起,就不會有上面的事情了。

這裡就涉及到 Spring Security 中的一個介面 AuthenticationEntryPoint ,該介面有一個實現類:LoginUrlAuthenticationEntryPoint ,該類中有一個方法 commence,如下:

/**
 * Performs the redirect (or forward) to the login form URL.
 */
public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) {
    String redirectUrl = null;
    if (useForward) {
        if (forceHttps && "http".equals(request.getScheme())) {
            redirectUrl = buildHttpsRedirectUrlForRequest(request);
        }
        if (redirectUrl == null) {
            String loginForm = determineUrlToUseForThisRequest(request, response,
                    authException);
            if (logger.isDebugEnabled()) {
                logger.debug("Server side forward to: " + loginForm);
            }
            RequestDispatcher dispatcher = request.getRequestDispatcher(loginForm);
            dispatcher.forward(request, response);
            return;
        }
    }
    else {
        redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
    }
    redirectStrategy.sendRedirect(request, response, redirectUrl);
}

首先我們從這個方法的註釋中就可以看出,這個方法是用來決定到底是要重定向還是要 forward,通過 Debug 追蹤,我們發現預設情況下 useForward 的值為 false,所以請求走進了重定向。

那麼我們解決問題的思路很簡單,直接重寫這個方法,在方法中返回 JSON 即可,不再做重定向操作,具體配置如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .anyRequest().authenticated()
            .formLogin()
            .loginProcessingUrl("/doLogin")
            .loginPage("/login")
            //其他配置
            .permitAll()
            .and()
            .csrf().disable().exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException authException) throws IOException, ServletException {
                resp.setContentType("application/json;charset=utf-8");
                PrintWriter out = resp.getWriter();
                RespBean respBean = RespBean.error("訪問失敗!");
                if (authException instanceof InsufficientAuthenticationException) {
                    respBean.setMsg("請求失敗,請聯絡管理員!");
                }
                out.write(new ObjectMapper().writeValueAsString(respBean));
                out.flush();
                out.close();
            }
        });
}

在 Spring Security 的配置中加上自定義的 AuthenticationEntryPoint 處理方法,該方法中直接返回相應的 JSON 提示即可。這樣,如果使用者再去直接訪問一個需要認證之後才可以訪問的請求,就不會發生重定向操作了,服務端會直接給瀏覽器一個 JSON 提示,瀏覽器收到 JSON 之後,該幹嘛幹嘛。

結語

好了,一個小小的重定向問題和小夥伴們分享下,不知道大家有沒有看懂呢?這也是我最近在重構微人事的時候遇到的問題。預計 11 月份,微人事的 Spring Boot 版本會升級到目前最新版,請小夥伴們留意哦。

關注公眾號【江南一點雨】,專注於 Spring Boot+微服務以及前後端分離等全棧技術,定期視訊教程分享,關注後回覆 Java ,領取鬆哥為你精心準備的 Java 乾貨!

相關推薦

Spring Security 前後分離登入非法請求直接返回 JSON

hello 各位小夥伴,國慶節終於過完啦,鬆哥也回來啦,今天開始咱們繼續發乾貨! 關於 Spring Security,鬆哥之前發過多篇文章和大家聊聊這個安全框架的使用: 手把手帶你入門 Spring Security! Spring Security 登入新增驗證碼 SpringSecurity 登入使用

七個開源的 Spring Boot 前後分離專案一定要收藏!

前後端分離已經在慢慢走進各公司的技術棧,根據鬆哥瞭解到的訊息,不少公司都已經切換到這個技術棧上面了。即使貴司目前沒有切換到這個技術棧上面,鬆哥也非常建議大家學習一下前後端分離開發,以免在公司幹了兩三年,SSH 框架用的滾瓜爛熟,出來卻發現自己依然沒有任何優勢! 其實前後端分離本身並不難,後段提供介面,前端做資

Spring Boot + Vue 前後分離開發前端網路請求封裝與配置

前端網路訪問,主流方案就是 Ajax,Vue 也不例外,在 Vue2.0 之前,網路訪問較多的採用 vue-resources,Vue2.0 之後,官方不再建議使用 vue-resources ,這個專案本身也停止維護,目前建議使用的方案是 axios。今天鬆哥就帶大家來看看 axios 的使用。 axios

前後分離師傅們應該知道的一些基本前端知識

跨域問題 分類 port 什麽是 格式 url 就會 是否 option 寫下此文,是因為本人作為前端小白,經常遇到同樣小白的後端,常常不得不三番五次科普一些前端的基礎知識,特此做些總結,也方便有下次的話,直接拿出來給對方看。 1. 什麽是ajax 對

為什麽前後分離你比從前更痛苦?

技術 book 設計 機制 需求 返回 痛苦 頁面 更改 ? 你有沒有遇到過: 前端代碼剛寫完,後端的接口又變了。 接口文檔永遠都是不對的。 測試工作永遠只能臨近上線才能開始。 為什麽前後端分離了,你比從前更痛苦? 前後端分離早已經不是新聞,當真正分離之

前後分離獲取不到session

在前後端分離的springboot專案中,進行圖片驗證時,第一次獲取驗證圖片後,我將code值加密後存放到了session中,打算在下一個請求進行圖片驗證時直接從session中獲取code值,然後進行對比。結果除錯時,在第二步過程中獲取的session一直為null。因此匹配結果一直false。當

Spring Boot前後分離Instant時間戳自定義解析

在SpringBoot專案中,前後端規定傳遞時間使用時間戳(精度ms). 以上為簡略實體類定義. 在實際使用過程中,發現Incident中的createdTime以及recoveryTime數值不對. 排查故障,前端去除時間戳後三位(即ms數),則時間基本吻合. 因此,可

vue前後分離專案解決跨域問題

最近公司新開發專案是前後端分離專案,前端用的是vue框架,在和前端除錯介面時存在拒絕跨域訪問403的情況。我這裡主要將解決的過程記錄一下。 什麼是跨域 跨域是瀏覽器的同源策略造成的,只要是域名、埠、協議有一不同,就會被當做是不同的域,之間的請求就被當做跨域操作。 設定同

前後分離專案使用session作為使用者狀態記錄

在使用前後端分離的專案中,我們一般選擇無狀態的請求方式,即web token;或者搭建快取伺服器,來準們儲存使用者的登入狀態。一般不會使用servlet的session來儲存使用者狀態,因為這種方式不太安全,而且前後端分離的專案中每次訪問的時候,所攜帶的sessionId也是不相同的,所以是

spring boot中spring security實現單點登入傳統模式(一)

單點登入是什麼? 一個系統中可能會引用別的很多系統。單點登入就是解決,一次登入,就可以訪問所有的系統。 每次瀏覽器向一個域名傳送http請求,會去查詢域名的cookie資訊拼接到http的header中傳送到伺服器。 cookie不能跨域。這個域是瀏覽器請求的域名,哪怕他們都是訪問一

前後分離。前端POST請求引數過長導致400錯誤解決辦法及分析

這兩天做好的功能要上線了。但是測試的時候忽然發現當POST提交資料量多大時,會導致後端報400錯誤。最開始以為瓶頸存在於tomcat,因為tomcat預設能接受的POST請求大小為2M,所以手動修改tomcat server.xml 檔案,將接受POST大小修改為不限制。

shiro配置 在springboot中前後分離整合shiro認證授權框架

一:介紹     Apache Shiro是Java的一個安全框架。由於它相對小而簡單,現在使用的人越來越多。     Authentication:身份認證/登入,驗證使用者是不是擁有相應的身份。     Authorization:授權,即許可權驗證,驗證某個已認證

Nginx學習總結(10)——Nginx前後分離將多個請求轉發到多個Tomcat負載均衡反向代理

一、談談“渲染” 相信好多人都挺聽過“渲染”這個詞,但不清楚它是什麼意思?前端開發以為這是後端的活兒,後端開發以為是前端的事兒,推著推著就不了了之。其實渲染很簡單,不說概念,直接舉例: 1、 後端渲染:以JSP為例,可以分成三步 a、編寫標籤或Java程式碼(可以稱之為模板

Django2.x前後分離開發跨域解決辦法

安裝django-cors-headers pip3 install django-cors-headers # 安裝django-cors-headers 在專案目錄裡面的settings.py新增下面的程式碼 INSTALLED_APPS = [ ... 'corsh

Maven多模組Dubbo分散式服務框架SpringMVC前後分離專案基礎搭建搭建過程出現的問題

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apac

spring + VUE 前後分離繞不過去的技術棧

首先感謝Spring在框架層面實現了多年構件重用的夙願,不僅如此還有Spring Boot 這樣的大大大紅包,java成就了Spring, 目前有點像Spring反哺Java, 讓Java看起來仍然活力四射。另一方面Vue的出現,以及Vue基礎上構建的Element-UI終於

ReactJS +Spring MVC前後分離 RESTful 互動

After building your project and after the prototype We may want to find a way to find a connection of React front to the Java API

前後分離時代Java 程式設計師的變與不變!

事情的起因是這樣的,有個星球的小夥伴向邀請鬆哥在知乎上回答一個問題,原題是: 前後端分離的時代,Java後臺程式設計師的技術建議? 鬆哥認真看了下這個問題,感覺對於初次接觸前後端分離的小夥伴來說,可能都會存在這樣的疑問,於是決定通過這篇文章和大家聊一聊這個話題。 我這裡還是儘量從一個 Java 程式設計

使用 Nginx 部署前後分離專案解決跨域問題

前後端分離這個問題其實鬆哥和大家聊過很多了,上週鬆哥把自己的兩個開源專案部署在伺服器上以幫助大家可以快速線上預覽(喜大普奔,兩個開源的 Spring Boot + Vue 前後端分離專案可以線上體驗了),然後群裡就有小夥伴想讓鬆哥來聊聊如何結合 Nginx 來部署前後端分離專案?今天我們就來聊一聊這個話題。

Vue+Spring Boot 前後分離的商城專案開源啦!

## 新蜂商城 Vue 移動端版本開源啦! 去年開源新蜂商城專案後,就一直在計劃這個專案 Vue 版本的改造,2020 年開始開發並且自己私下一直在測試,之前也有文章介紹過測試過程和存在的問題,修改完成後,於 5 月底將 Vue 版本的所有程式碼開源了,只是後面一直太忙,沒有時間整理這篇文章。 現在,向大