亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringSecurity表單配置之登錄成功及頁(yè)面跳轉(zhuǎn)原理解析

 更新時(shí)間:2023年12月05日 09:58:13   作者:陳橙橙丶  
這篇文章主要介紹了SpringSecurity表單配置之登錄成功及頁(yè)面跳轉(zhuǎn)原理解析,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

登錄表單配置

在上一篇文章中,我們介紹了,基本認(rèn)證以及默認(rèn)用戶名和密碼以及頁(yè)面SpringSecurity是怎樣幫我們生成的,這里我們就來(lái)看一下登錄表單的詳細(xì)配置。

項(xiàng)目準(zhǔn)備

導(dǎo)入依賴

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

編寫(xiě)登錄頁(yè)面(login.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>登錄</title>
    <link  rel="external nofollow" rel="stylesheet"
    id="bootstrap-css"
    />
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js">
    </script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js">
    </script>
</head>
<style>
</style>
<body>
    <div id="login">
        <div class="container">
            <div id="login-row" class="row justify-content-center align-item-center">
                <div id="login-colum" class="col-md-6">
                    <div id="login-box" class="col-md-12">
                        <form id="login-form" class="form" action="/doLogin" method="post">
                            <h3 class="text-center text-info">登錄</h3>
                            <div class="form-group">
                                <label for="username" class="text-info">用戶名:</label><br>
                                <input type="text" name="uname" id="username" class="form-control">
                            </div>
                            <div class="form-group">
                                <label for="password" class="text-info">密碼:</label><br>
                                <input type="text" name="passwd" id="password" class="form-control">
                            </div>
                            <div class="form-group">
                                <input type="submit" name="submit"  class="btn btn-info btn-md" value="登錄">
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

提供兩個(gè)測(cè)試接口

@GetMapping("/hello")
    public String hello(){
        return "hello springboot security";
    }
    @GetMapping("/index")
    public String index(){
        return "login success";
    }

自定義用戶名密碼

spring.security.user.name=test
spring.security.user.password=123456
spring.security.user.roles=admin,user

提供SpringSecurity配置類

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated() 
                .and().formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/doLogin")
                .defaultSuccessUrl("/index")
                .failureUrl("/login.html")
                .usernameParameter("uname")
                .passwordParameter("passwd")
                .permitAll()
                .and()
                .csrf().disable();
    }
}

在SpringSecurity中,如果我們需要自定義配置,基本上都是繼承WebSecurityConfigurerAdapter來(lái)實(shí)現(xiàn)的,當(dāng)然WebSecurityConfigurerAdapter本身的配置還是比較復(fù)雜,同時(shí)也是比較豐富的,這里不細(xì)說(shuō),后續(xù)會(huì)詳細(xì)介紹。

  • 首先configure方法中是一個(gè)鏈?zhǔn)脚渲?,?dāng)然也可以不用鏈?zhǔn)脚渲?,每個(gè)屬性配置完畢后再?gòu)膆ttp重新寫(xiě)起
  • authorizeRequests()方法表示開(kāi)啟權(quán)限配置
    • anyRequest().authenticated()表示所有的請(qǐng)求都要認(rèn)證之后才能訪問(wèn)
  • and()方法,該方法會(huì)返回一個(gè)HttpSecurityBuilder對(duì)象的一個(gè)子類(實(shí)際上就算HttpSecurity),所以and()方法相當(dāng)于又回到HttpSecurity實(shí)例,重新開(kāi)啟新一輪的配置。
  • formLogin()表示開(kāi)啟表單登錄配置:
    • loginPage:用來(lái)配置登錄頁(yè)面地址
    • loginProcessingUrl:用來(lái)配置接口登錄接口地址
    • defaultSuccessUrl:表示登錄成功后跳轉(zhuǎn)地址
    • failureUrl:表示登錄失敗后跳轉(zhuǎn)的地址
    • usernameParameter:表示登錄用戶名的參數(shù)名稱
    • passwordParameter:表示密碼的參數(shù)名稱
    • permitAll:可以理解成兩個(gè)and()之間的所有方法地址不需要認(rèn)證攔截(白名單)。

需要注意的是loginProcessingUrl、usernameParameterpasswordParameter需要和login.html中登錄表單配置一致

最后csrf().disable()表示禁用CSRF防御功能,SpringSecurity自帶了CSRF防御機(jī)制,但是我們這里為了測(cè)試方便,先將CSRF防御機(jī)制關(guān)閉。

啟動(dòng)項(xiàng)目訪問(wèn)http://localhost:8080/index

輸入配置的用戶名/密碼:test/123456,然后就能訪問(wèn)到/index接口了

配置細(xì)節(jié)

上面我們說(shuō)到defaultSuccessUrl和failureUrl表示用戶登錄失敗后的跳轉(zhuǎn)地址。關(guān)于登錄成功和登錄失敗,除了這兩個(gè)方法之外,還有另外兩個(gè)方法可以配置

登錄成功

  • successForwardUrl
  • defaultSuccessUrl

defaultSuccessUrl前者表示當(dāng)用戶登錄成功之后,會(huì)自動(dòng)重定向到登錄之前的地址上,如果用戶本身就是直接訪問(wèn)的登錄頁(yè)面,則登錄成功之后就會(huì)重定向到defaultSuccessUrl指定的頁(yè)面中。例如用戶在未認(rèn)證的情況下,訪問(wèn)了/hello頁(yè)面,此時(shí)會(huì)重定向到登錄頁(yè)面,登錄成功后,就會(huì)自動(dòng)重定向到/hello頁(yè)面;而用戶如果一開(kāi)始就是訪問(wèn)到登錄頁(yè)面,則登錄成功后就會(huì)自動(dòng)重定向到defaultSuccessUrl指定的頁(yè)面

successForwardUrl則不會(huì)考慮用戶之前所訪問(wèn)地址,只要用戶登錄成功,就會(huì)通過(guò)服務(wù)器端跳轉(zhuǎn)到successForwardUrl所指定的頁(yè)面。

defaultSuccessUrl有一個(gè)重載方法,如果重載方法的第二個(gè)參數(shù)傳入true,則它和successForwardUrl效果類似,即不考慮用戶之前的訪問(wèn)地址,只要登錄成功就重定向到指定頁(yè)面。不同之處在于defaultSuccessUrl是通過(guò)重定向?qū)崿F(xiàn)的跳轉(zhuǎn)(客戶端跳轉(zhuǎn)),而successForwardUrl是通過(guò)服務(wù)器端跳轉(zhuǎn)實(shí)現(xiàn)的。

無(wú)論是successForwardUrl還是defaultSuccessUrl,最終所有配置的都是AuthenticationSuccessHandler接口的實(shí)例。

SpringSecurity中專門(mén)提供了AuthenticationSuccessHandler接口用來(lái)處理登錄成功事項(xiàng)

public interface AuthenticationSuccessHandler {
    default void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
        this.onAuthenticationSuccess(request, response, authentication);
        chain.doFilter(request, response);
    }
    void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException;
}

由上述代碼可以看到AuthenticationSuccessHandler接口中一共定義了兩個(gè)方法,一個(gè)是default方法,此方法是SpringSecurity5.2開(kāi)始加入的,在處理特定的認(rèn)證請(qǐng)求Authentication Filter中會(huì)用到;另外一個(gè)非default方法,則用來(lái)處理登錄成功的具體事項(xiàng),其中authentication參數(shù)保存了登錄成功的用戶信息。

AuthenticationSuccessHandler接口一共有三個(gè)實(shí)現(xiàn)類:

在這里插入圖片描述

(1)、SimpleUrlAuthenticationSuccessHandler繼承自AbstractAuthenticationTargetUrlRequestHandler,通過(guò)AbstractAuthenticationTargetUrlRequestHandler中的handle方法實(shí)現(xiàn)請(qǐng)求重定向

(2)、SavedRequestAwareAuthenticationSuccessHandler在SimpleUrlAuthenticationSuccessHandler的基礎(chǔ)之上增加了請(qǐng)求緩存的功能,可以記錄之前請(qǐng)求的地址,進(jìn)而在登錄成功之后重定向到一開(kāi)始訪問(wèn)的地址。

(3)、ForwardAuthenticationSuccessHandler的實(shí)現(xiàn)就比較容易,就是一個(gè)服務(wù)端跳轉(zhuǎn)。

我們來(lái)重點(diǎn)看一下SavedRequestAwareAuthenticationSuccessHandler和ForwardAuthenticationSuccessHandler

public class SavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
	protected final Log logger = LogFactory.getLog(this.getClass());
	private RequestCache requestCache = new HttpSessionRequestCache();
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws ServletException, IOException {
		SavedRequest savedRequest = this.requestCache.getRequest(request, response);
		if (savedRequest == null) {
			super.onAuthenticationSuccess(request, response, authentication);
			return;
		}
		String targetUrlParameter = getTargetUrlParameter();
		if (isAlwaysUseDefaultTargetUrl()
				|| (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
			this.requestCache.removeRequest(request, response);
			super.onAuthenticationSuccess(request, response, authentication);
			return;
		}
		clearAuthenticationAttributes(request);
		// Use the DefaultSavedRequest URL
		String targetUrl = savedRequest.getRedirectUrl();
		getRedirectStrategy().sendRedirect(request, response, targetUrl);
	}
	public void setRequestCache(RequestCache requestCache) {
		this.requestCache = requestCache;
	}
}

這里的核心方法就是 onAuthenticationSuccess

(1)、首先從requestCache中獲取緩存下來(lái)的請(qǐng)求,如果沒(méi)有獲取到緩存請(qǐng)求,就說(shuō)明用戶在登錄頁(yè)面之前并沒(méi)有訪問(wèn)其他頁(yè)面,此時(shí)調(diào)用父類的方法來(lái)處理,最終會(huì)重定向到defaultSuccessUrl指定的地址

(2)、如果緩存請(qǐng)求不為空,則會(huì)獲取一個(gè)targetUrlParameter,這個(gè)是用戶顯示指定的,希望登錄成功重定向的地址,例如用戶發(fā)送的登錄請(qǐng)求是http://localhost:8080/doLogin?target=/hello,這就表示當(dāng)用戶登錄成功之后。希望自動(dòng)重定向到/hello這個(gè)接口,getTargetUrlParameter就是要獲取重定向地址參數(shù)的key,也就是上面的target,拿到target之后,就可以獲取到重定向地址了。

(3)、如果targetUrlParameter存在,或者用戶設(shè)置了alwaysUseDefaultTargetUrl為true,這個(gè)時(shí)候緩存下來(lái)的請(qǐng)求就沒(méi)有意義了。此時(shí)會(huì)直接調(diào)用父類的onAuthenticationSuccess方法完成重定向。targetUrlParameter存在,則直接重定向到targetUrlParameter指定的地址。alwaysUseDefaultTargetUrl為true,則直接重定向到defaultSuccessUrl指定的地址。如果alwaysUseDefaultTargetUrl和targetUrlParameter同時(shí)滿足,則重定向到defaultSuccessUrl指定的地址。

(4)、如果前面的條件都不滿足,那么最終會(huì)從緩存請(qǐng)求saveRequest中獲取重定向地址,然后進(jìn)行重定向操作。

這就是SavedRequestAwareAuthenticationSuccessHandler的實(shí)現(xiàn)邏輯,開(kāi)發(fā)者也可以配置自己的SavedRequestAwareAuthenticationSuccessHandler,代碼如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and().formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/doLogin")
                .successHandler(successHandler())
//                .defaultSuccessUrl("/index")
                .failureUrl("/login.html")
                .usernameParameter("uname")
                .passwordParameter("passwd")
                .permitAll()
                .and()
                .csrf().disable();
    }
    SavedRequestAwareAuthenticationSuccessHandler successHandler(){
        SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
        handler.setDefaultTargetUrl("/hello");
        handler.setTargetUrlParameter("target");
        return handler;
    }
}

然后在上篇文章中的表單中,修改一下action的參數(shù)

action="/doLogin?target=http://www.baidu.com"

這樣當(dāng)我們登錄成功之后就可以跳轉(zhuǎn)到百度了,如果不指定action的target就會(huì)跳轉(zhuǎn)到我們上面默認(rèn)的/hello接口

當(dāng)我們通過(guò)successForwardUrl來(lái)設(shè)置登錄成功后重定向地址時(shí),實(shí)際上對(duì)應(yīng)的實(shí)現(xiàn)類就是ForwardAuthenticationSuccessHandler,它的源碼特別簡(jiǎn)單,就是一個(gè)服務(wù)端轉(zhuǎn)發(fā),如下:

public class ForwardAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
	private final String forwardUrl;
	/**
	 * @param forwardUrl
	 */
	public ForwardAuthenticationSuccessHandler(String forwardUrl) {
		Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> "'" + forwardUrl + "' is not a valid forward URL");
		this.forwardUrl = forwardUrl;
	}
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		request.getRequestDispatcher(this.forwardUrl).forward(request, response);
	}
}

上述代碼可以看到,主要共嗯那個(gè)就是調(diào)用getRequestDispatcher方法進(jìn)行服務(wù)端轉(zhuǎn)發(fā),AuthenticationSuccessHandler默認(rèn)的三個(gè)實(shí)現(xiàn)類,無(wú)論是哪一個(gè),都是用來(lái)處理頁(yè)面跳轉(zhuǎn)的。有時(shí)候頁(yè)面跳轉(zhuǎn)并不能滿足我們的需求,特別是現(xiàn)在的前后的分離開(kāi)發(fā)中,用戶登錄成功之后,就不需要跳轉(zhuǎn)頁(yè)面了,只需要給前端返回一個(gè)JSON數(shù)據(jù)即可,告訴前端登錄成功還是失敗,前端收到消息后自行處理,像這樣的需求,我們可以通過(guò)自定義AuthenticationSuccessHandler的實(shí)現(xiàn)類來(lái)完成,如下:

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        HashMap<String,Object> resp = new HashMap<>();
        resp.put("status",200);
        resp.put("msg","登錄成功");
        ObjectMapper om = new ObjectMapper();
        final String writeValueAsString = om.writeValueAsString(resp);
        response.getWriter().write(writeValueAsString);
    }
}

然后在WebSecurity中配置

http.successHandler(new MyAuthenticationSuccessHandler());

配置完成之后,此時(shí)登錄成功,就不會(huì)進(jìn)行頁(yè)面添磚了,而是返回一段JSON字符串。

關(guān)于登錄失敗的,會(huì)在下一篇中詳細(xì)講解。

到此這篇關(guān)于SpringSecurity表單配置之登錄成功及頁(yè)面跳轉(zhuǎn)原理的文章就介紹到這了,更多相關(guān)SpringSecurity登錄成功跳轉(zhuǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot啟動(dòng)應(yīng)用及回調(diào)監(jiān)聽(tīng)原理解析

    SpringBoot啟動(dòng)應(yīng)用及回調(diào)監(jiān)聽(tīng)原理解析

    這篇文章主要介紹了SpringBoot啟動(dòng)應(yīng)用及回調(diào)監(jiān)聽(tīng)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 手把手教你在eclipse創(chuàng)建第一個(gè)java?web項(xiàng)目并運(yùn)行

    手把手教你在eclipse創(chuàng)建第一個(gè)java?web項(xiàng)目并運(yùn)行

    Eclipse是用來(lái)做開(kāi)發(fā)的自由集成開(kāi)發(fā)環(huán)境,這也是很多java程序員會(huì)使用的開(kāi)發(fā)環(huán)境,所以可以使用eclipse創(chuàng)建javaweb項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于如何在eclipse創(chuàng)建第一個(gè)java?web項(xiàng)目并運(yùn)行的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • java判斷字符串是否為數(shù)字的方法小結(jié)

    java判斷字符串是否為數(shù)字的方法小結(jié)

    這篇文章主要介紹了java判斷字符串是否為數(shù)字的方法,分別講述了使用Java自帶函數(shù)、正則表達(dá)式及ascii碼三種方法進(jìn)行字符串判斷的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • json轉(zhuǎn)換成java對(duì)象示例

    json轉(zhuǎn)換成java對(duì)象示例

    這篇文章主要介紹了json轉(zhuǎn)換成java對(duì)象示例,需要的朋友可以參考下
    2014-04-04
  • Java中的IO流之字符流Reader和Writer

    Java中的IO流之字符流Reader和Writer

    這篇文章主要介紹了Java中的IO流之字符流Reader和Writer,Reader : 和InputStream的唯一的區(qū)別就在于讀的數(shù)據(jù)單位不同,繼承自Reader的流都是用于向程序中輸入數(shù)據(jù),且數(shù)據(jù)的單位為字符16bit,需要的朋友可以參考下
    2023-10-10
  • 從千千靜聽(tīng)歌詞服務(wù)器獲取lrc歌詞示例分享

    從千千靜聽(tīng)歌詞服務(wù)器獲取lrc歌詞示例分享

    這篇文章主要介紹了使用PHP從千千靜聽(tīng)歌詞服務(wù)器獲取lrc歌詞的方法,大家參考使用吧
    2014-01-01
  • Java中String類常用類型實(shí)例總結(jié)

    Java中String類常用類型實(shí)例總結(jié)

    在我們開(kāi)發(fā)中經(jīng)常會(huì)用到很多的常用的工具類,這里做一個(gè)總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中String類常用類型的相關(guān)資料,String類代表字符串,需要的朋友可以參考下
    2021-12-12
  • 詳解spring 配置的兩種方式:JAVA配置和注解配置

    詳解spring 配置的兩種方式:JAVA配置和注解配置

    這篇文章主要介紹了詳解spring 配置的兩種方式:JAVA配置和注解配置,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 詳解Mybatis框架SQL防注入指南

    詳解Mybatis框架SQL防注入指南

    這篇文章主要介紹了詳解Mybatis框架SQL防注入指南,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • mybatis-plus分頁(yè)無(wú)效問(wèn)題解決

    mybatis-plus分頁(yè)無(wú)效問(wèn)題解決

    本文主要介紹了mybatis-plus分頁(yè)無(wú)效問(wèn)題解決,原因是配置分頁(yè)插件的版本問(wèn)題,舊版本和新版本的MyBatis-Plus需要不同的分頁(yè)配置,感興趣的可以了解一下
    2025-03-03

最新評(píng)論