91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringSecurity怎么實現前后端分離

發布時間:2023-03-30 11:14:59 來源:億速云 閱讀:98 作者:iii 欄目:開發技術

今天小編給大家分享一下SpringSecurity怎么實現前后端分離的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    Spring Security存在的問題

    前后端分離模式是指由前端控制頁面路由,后端接口也不再返回html數據,而是直接返回業務數據,數據一般是JSON格式。

    Spring Security默認支持的表單認證方式,會存在兩個問題:

    • 表單的HTTP Content-Type是application/x-www-form-urlencoded,不是JSON格式。

    • Spring Security會在用戶未登錄或登錄成功時會發起頁面重定向,重定向到登錄頁或登錄成功頁面。

    要支持前后端分離的模式,我們要對這些問題進行改造。

    改造Spring Security的認證方式

    1. 登錄請求改成JSON方式

    Spring Security默認提供賬號密碼認證方式,具體實現是在UsernamePasswordAuthenticationFilter類中。因為是表單提交,所以Filter中用request.getParameter(this.usernameParameter) 來獲取用戶賬號和密碼信息。當我們將請求類型改成application/json后,getParameter方法就獲取不到信息。

    要解決這個問題,就要新建一個Filter來替換UsernamePasswordAuthenticationFilter ,然后重新實現獲取用戶的方法。

    1.1 新建JSON版Filter - JsonUsernamePasswordAuthenticationFilter
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import lombok.SneakyThrows;
    import org.springframework.data.util.Pair;
    import org.springframework.security.authentication.AuthenticationServiceException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    public class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
                throws AuthenticationException {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }
            Pair<String, String> usernameAndPassword = obtainUsernameAndPassword(request);
            String username = usernameAndPassword.getFirst();
            username = (username != null) ? username.trim() : "";
            String password = usernameAndPassword.getSecond();
            password = (password != null) ? password : "";
            UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
                    password);
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
        @SneakyThrows
        private Pair<String, String> obtainUsernameAndPassword(HttpServletRequest request) {
            JSONObject map = JSON.parseObject(request.getInputStream(), JSONObject.class);
            return Pair.of(map.getString(getUsernameParameter()), map.getString(getPasswordParameter()));
        }
    }
    1.2 新建Configurer來注冊Filter - JsonUsernamePasswordLoginConfigurer

    注冊Filter有兩種方式,一給是直接調用httpSecurity的addFilterAt(Filter filter, Class<? extends Filter> atFilter) ,另一個是通過AbstractHttpConfigurer 來注冊。因為我們繼承了原來的賬密認證方式,考慮到兼容原有邏輯,我們選擇Spring Security默認的Configurer注冊方式來注冊Filter。AbstractHttpConfigurer 在初始化 UsernamePasswordAuthenticationFilter 的時候,會額外設置一些信息。

    新建一個JsonUsernamePasswordLoginConfigurer直接繼承AbstractAuthenticationFilterConfigurer。

    import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
    import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    import org.springframework.security.web.util.matcher.RequestMatcher;
    public final class JsonUsernamePasswordLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
            AbstractAuthenticationFilterConfigurer<H, JsonUsernamePasswordLoginConfigurer<H>, JsonUsernamePasswordAuthenticationFilter> {
    	public JsonUsernamePasswordLoginConfigurer() {
    		super(new JsonUsernamePasswordAuthenticationFilter(), null);
    	}
            // 去掉登錄處理接口的權限校驗
    	@Override
    	protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
    		return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    	}
    }
    1.3 將自定義Configurer注冊到HttpSecurity上

    這一步比較簡單,我們先關閉原來的表單認證,然后注冊我們自己的Configurer,實現JSON版認證方式。

    http
        .formLogin().disable()
        .apply(new JsonUsernamePasswordLoginConfigurer<>())

    經過這三步,Spring Security就能識別JSON格式的用戶信息了。

    2. 關閉頁面重定向

    有幾個場景會觸發Spring Security的重定向:

    • 當前用戶未登錄,重定向到登錄頁面

    • 登錄驗證成功,重定向到默認頁面

    • 退出登錄成功,重定向到默認頁面

    我們要對這幾個場景分別處理,給前端返回JSON格式的描述信息,而不是發起重定向。

    2.1 當前用戶未登錄

    用戶發起未登錄的請求會被AuthorizationFilter攔截,并拋出AccessDeniedException異常。異常被AuthenticationEntryPoint處理,默認會觸發重定向到登錄頁。Spring Security開放了配置,允許我們自定義AuthenticationEntryPoint。那么我們就通過自定義AuthenticationEntryPoint來取消重定向行為,將接口改為返回JSON信息。

    http.exceptionHandling(it -> it.authenticationEntryPoint((request, response, authException) -> {
            String msg = "{\\"msg\\": \\"用戶未登錄\\"}";
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            PrintWriter writer = response.getWriter();
            writer.write(msg);
            writer.flush();
            writer.close();
        }))
    2.2 登錄成功/失敗

    登錄成功或失敗后的行為由AuthenticationSuccessHandler 和AuthenticationFailureHandler 來控制。原來是在**formLogin(it->it.successHandler(null))**里配置它們,由于上面我們自定義了JsonUsernamePasswordLoginConfigurer ,所以要在我們自己的Configurer 上配置AuthenticationSuccessHandler 和AuthenticationFailureHandler 。

    http
        .formLogin().disable()
        .apply((SecurityConfigurerAdapter) new JsonUsernamePasswordLoginConfigurer<>()
                .successHandler((request, response, authentication) -> {
    		String msg = "{\\"msg\\": \\"登錄成功\\"}";
    		response.setStatus(HttpStatus.OK.value());
    		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    		PrintWriter writer = response.getWriter();
    		writer.write(msg);
    		writer.flush();
    		writer.close();
                })
                .failureHandler((request, response, exception) -> {
                    String msg = "{\\"msg\\": \\"用戶名密碼錯誤\\"}";
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
    		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    		PrintWriter writer = response.getWriter();
    		writer.write(msg);
    		writer.flush();
    		writer.close();
                }));
    2.3 退出登錄

    退出登錄是在LogoutConfigurer配置,退出成功后,會觸發LogoutSuccessHandler操作,我們也重寫它的處理邏輯。

    http.logout(it -> it
            .logoutSuccessHandler((request, response, authentication) -> {
                String msg = "{\\"msg\\": \\"退出成功\\"}";
                response.setStatus(HttpStatus.OK.value());
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                PrintWriter writer = response.getWriter();
                writer.write(msg);
                writer.flush();
                writer.close();
            }))

    3. 最后處理CSRF校驗

    前后端分離后,如果頁面是放在CDN上,那么前段直至發起登錄請求之前,都沒機會從后端拿到CSRF Token。所以,登錄請求會被Spring Security的CsrfFilter攔截。

    要避免這種情況,一種方式是發起登錄請求前,先調用接口獲取CSRF Token;另一種方式是先關閉登錄接口的CSRF校驗。方式二配置如下:

    http.csrf(it -> it.ignoringRequestMatchers("/login", "POST"))

    以上就是“SpringSecurity怎么實現前后端分離”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    辽源市| 普兰县| 罗定市| 石嘴山市| 石泉县| 汝阳县| 广安市| 淮安市| 兴海县| 贵溪市| 亚东县| 大丰市| 田东县| 革吉县| 阿城市| 宜昌市| 当雄县| 吴江市| 彭泽县| 梁山县| 民丰县| 屏边| 灵石县| 昌乐县| 张北县| 木兰县| 德兴市| 扎鲁特旗| 黔西县| 佛山市| 阳原县| 察隅县| 南岸区| 沐川县| 广昌县| 秦皇岛市| 澎湖县| 泌阳县| 崇明县| 上思县| 嵊泗县|