最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring security中的默認(rèn)登錄頁(yè)源碼跟蹤

 更新時(shí)間:2021年11月08日 08:27:39   作者:尋找的路上  
原來Spring Security有一個(gè)默認(rèn)的WebSecurityConfigurerAdapter,發(fā)現(xiàn)其中有一個(gè)init方法,于是在這個(gè)方法打了斷點(diǎn),在應(yīng)用啟動(dòng)的時(shí)候進(jìn)行跟蹤,這篇文章主要介紹了spring security之 默認(rèn)登錄頁(yè)源碼跟蹤,需要的朋友可以參考下

​2021年的最后2個(gè)月,立個(gè)flag,要把Spring Security和Spring Security OAuth2的應(yīng)用及主流程源碼研究透徹!

​項(xiàng)目中使用過Spring Security的童鞋都知道,當(dāng)我們沒有單獨(dú)自定義登錄頁(yè)時(shí),Spring Security自己在初始化的時(shí)候會(huì)幫我們配置一個(gè)默認(rèn)的登錄頁(yè),之前一直疑問默認(rèn)登錄頁(yè)是怎么配置的,今晚特地找了源碼跟一下。

springboot項(xiàng)目依賴

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

在項(xiàng)目中隨意編寫一個(gè)接口,然后進(jìn)行訪問

@GetMapping("/")
public String hello() {
   return "hello, spring security";
}

在tomcat默認(rèn)端口8080,localhost:8080 下訪問該接口,spring security會(huì)幫我們將路徑重定向到默認(rèn)的登錄頁(yè)

​那么這個(gè)默認(rèn)頁(yè)是怎么來的呢?
原來Spring Security有一個(gè)默認(rèn)的WebSecurityConfigurerAdapter,發(fā)現(xiàn)其中有一個(gè)init方法,于是在這個(gè)方法打了斷點(diǎn),在應(yīng)用啟動(dòng)的時(shí)候進(jìn)行跟蹤。

​跟蹤getHttp()方法,this.disableDefaults變量默認(rèn)為false,意味著將會(huì)執(zhí)行applyDefaultConfiguration(this.http);方法。查看applyDefaultConfiguration方法

public void init(WebSecurity web) throws Exception {
    // 首先配置security要攔截的哪些http請(qǐng)求
   HttpSecurity http = getHttp();
   web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
      FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
      web.securityInterceptor(securityInterceptor);
   });
}

protected final HttpSecurity getHttp() throws Exception {
		if (this.http != null) {
			return this.http;
		}
		AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
		this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
		AuthenticationManager authenticationManager = authenticationManager();
		this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
		Map<Class<?>, Object> sharedObjects = createSharedObjects();
		this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
		if (!this.disableDefaults) {
            // 默認(rèn)的配置將會(huì)走這個(gè)分支
			applyDefaultConfiguration(this.http);
			ClassLoader classLoader = this.context.getClassLoader();
			List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
					.loadFactories(AbstractHttpConfigurer.class, classLoader);
			for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
				this.http.apply(configurer);
			}
		}
		configure(this.http);
		return this.http;
	}

查看applyDefaultConfiguration(this.http)方法,發(fā)現(xiàn)http對(duì)象new了一個(gè)DefaultLoginPageConfigurer對(duì)象屬性,

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
   http.csrf();
   http.addFilter(new WebAsyncManagerIntegrationFilter());
   http.exceptionHandling();
   http.headers();
   http.sessionManagement();
   http.securityContext();
   http.requestCache();
   http.anonymous();
   http.servletApi();
   http.apply(new DefaultLoginPageConfigurer<>());
   http.logout();
}

​查看DefaultLoginPageConfigurer類定義,發(fā)現(xiàn)它在初始化的同時(shí),它也初始化了自己的2個(gè)私有成員變量,分別是DefaultLoginPageGeneratingFilter默認(rèn)登錄頁(yè)面生成Filter,DefaultLogoutPageGeneratingFilter默認(rèn)登錄頁(yè)面Filter, 名字起得很好,見名知意,我們馬山知道這2個(gè)類的含義。

​查看DefaultLoginPageGeneratingFilter的類成員變量,發(fā)現(xiàn)定義了一系列跟登錄有關(guān)的成員變量,包括登錄、登錄等路徑,默認(rèn)的登錄頁(yè)面路徑是"/login"

public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {

   public static final String DEFAULT_LOGIN_PAGE_URL = "/login";

   public static final String ERROR_PARAMETER_NAME = "error";

   private String loginPageUrl;

   private String logoutSuccessUrl;

   private String failureUrl;

   private boolean formLoginEnabled;
    .....

​再結(jié)合類名思考,發(fā)現(xiàn)是個(gè)Filter類,那么它們應(yīng)該都會(huì)重新Filter的doFilter(ServletRequest request, ServletResponse response, FilterChain chain)方法,我們查看一下DefaultLoginPageConfigurer類的``doFilter方法,果然,在doFilter`方法中發(fā)現(xiàn)了生成默認(rèn)登錄頁(yè)面的方法。

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    // 判斷當(dāng)前的請(qǐng)求是否被認(rèn)證通過
   boolean loginError = isErrorPage(request);
   boolean logoutSuccess = isLogoutSuccess(request);
   if (isLoginUrlRequest(request) || loginError || logoutSuccess) {
       // 當(dāng)前請(qǐng)求認(rèn)證失敗的話,將會(huì)執(zhí)行這個(gè)分支
      String loginPageHtml = generateLoginPageHtml(request, loginError, logoutSuccess);
      response.setContentType("text/html;charset=UTF-8");
      response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
      response.getWriter().write(loginPageHtml);
      return;
   }
   chain.doFilter(request, response);
}

private String generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess) {
   String errorMsg = "Invalid credentials";
   if (loginError) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         AuthenticationException ex = (AuthenticationException) session
               .getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
         errorMsg = (ex != null) ? ex.getMessage() : "Invalid credentials";
      }
   }
   String contextPath = request.getContextPath();
   StringBuilder sb = new StringBuilder();
   sb.append("<!DOCTYPE html>\n");
   sb.append("<html lang=\"en\">\n");
   sb.append("  <head>\n");
   sb.append("    <meta charset=\"utf-8\">\n");
   sb.append("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n");
   sb.append("    <meta name=\"description\" content=\"\">\n");
   sb.append("    <meta name=\"author\" content=\"\">\n");
   sb.append("    <title>Please sign in</title>\n");
   sb.append("    <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" "
         + "rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n");
   sb.append("    <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" "
         + "rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n");
   sb.append("  </head>\n");
   sb.append("  <body>\n");
   sb.append("     <div class=\"container\">\n");
   if (this.formLoginEnabled) {
      sb.append("      <form class=\"form-signin\" method=\"post\" action=\"" + contextPath
            + this.authenticationUrl + "\">\n");
      sb.append("        <h2 class=\"form-signin-heading\">Please sign in</h2>\n");
      sb.append(createError(loginError, errorMsg) + createLogoutSuccess(logoutSuccess) + "        <p>\n");
      sb.append("          <label for=\"username\" class=\"sr-only\">Username</label>\n");
      sb.append("          <input type=\"text\" id=\"username\" name=\"" + this.usernameParameter
            + "\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n");
      sb.append("        </p>\n");
      sb.append("        <p>\n");
      sb.append("          <label for=\"password\" class=\"sr-only\">Password</label>\n");
      sb.append("          <input type=\"password\" id=\"password\" name=\"" + this.passwordParameter
            + "\" class=\"form-control\" placeholder=\"Password\" required>\n");
      sb.append("        </p>\n");
      sb.append(createRememberMe(this.rememberMeParameter) + renderHiddenInputs(request));
      sb.append("        <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n");
      sb.append("      </form>\n");
   }
   if (this.openIdEnabled) {
      sb.append("      <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"" + contextPath
            + this.openIDauthenticationUrl + "\">\n");
      sb.append("        <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n");
  ......
   return sb.toString();
}

​我們發(fā)現(xiàn)generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess)這個(gè)方法中使用了最原始的Servlet寫html頁(yè)面的方法,將登錄頁(yè)的html代碼寫到字符串中寫出到前端展示。到這里,我們就大體知道默認(rèn)登錄頁(yè)面及登出頁(yè)面是怎么生成的了。

​默認(rèn)登錄頁(yè)到這里就結(jié)束了,有興趣的可以關(guān)注下,接下來會(huì)繼續(xù)寫springsecurity的自定義表單認(rèn)證、授權(quán)、會(huì)話等內(nèi)容剖析。距離2022年只剩54天!

到此這篇關(guān)于spring security之 默認(rèn)登錄頁(yè)源碼跟蹤的文章就介紹到這了,更多相關(guān)spring security登錄頁(yè)源碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java轉(zhuǎn)發(fā)和重定向的區(qū)別

    java轉(zhuǎn)發(fā)和重定向的區(qū)別

    這篇文章主要介紹了java轉(zhuǎn)發(fā)和重定向的區(qū)別,需要的朋友可以參考下
    2014-10-10
  • Mybatis批量插入和批量更新失敗問題

    Mybatis批量插入和批量更新失敗問題

    這篇文章主要介紹了Mybatis批量插入和批量更新失敗問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • IDEA生成javadoc的實(shí)現(xiàn)步驟

    IDEA生成javadoc的實(shí)現(xiàn)步驟

    Javadoc是一種用于生成API文檔的工具,它可以根據(jù)代碼中特定格式的注釋自動(dòng)生成文檔,本文主要介紹了IDEA生成javadoc的實(shí)現(xiàn)步驟,感興趣的可以了解一下
    2023-10-10
  • SpringBoot?Security的自定義異常處理

    SpringBoot?Security的自定義異常處理

    這篇文章主要介紹了SpringBoot?Security的自定義異常處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java線程封閉之棧封閉和ThreadLocal

    java線程封閉之棧封閉和ThreadLocal

    這篇文章主要介紹了java線程封閉之棧封閉和ThreadLocal,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 關(guān)于SpringBoot中的請(qǐng)求映射及使用

    關(guān)于SpringBoot中的請(qǐng)求映射及使用

    這篇文章主要介紹了關(guān)于SpringBoot中的請(qǐng)求映射及使用,Spring Boot 中的授權(quán)機(jī)制,包括基于角色的授權(quán)和基于資源的授權(quán),同時(shí),我們也將給出相應(yīng)的代碼示例,幫助讀者更好地理解和應(yīng)用這些授權(quán)機(jī)制,需要的朋友可以參考下
    2023-07-07
  • @CacheEvict 清除多個(gè)key的實(shí)現(xiàn)方式

    @CacheEvict 清除多個(gè)key的實(shí)現(xiàn)方式

    這篇文章主要介紹了@CacheEvict 清除多個(gè)key的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java實(shí)現(xiàn)全排列的三種算法詳解

    Java實(shí)現(xiàn)全排列的三種算法詳解

    從n個(gè)不同元素中任取m(m≤n)個(gè)元素,按照一定的順序排列起來,叫做從n個(gè)不同元素中取出m個(gè)元素的一個(gè)排列。當(dāng)m=n時(shí)所有的排列情況叫全排列。本文總結(jié)了Java實(shí)現(xiàn)全排列的三種算法,需要的可以參考下
    2022-06-06
  • log4j2 RollingRandomAccessFile配置過程

    log4j2 RollingRandomAccessFile配置過程

    這篇文章主要介紹了log4j2 RollingRandomAccessFile配置過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java 初識(shí)CRM之項(xiàng)目思路解析

    Java 初識(shí)CRM之項(xiàng)目思路解析

    本篇文章意在幫助大家了解CRM的一些基本概念,介紹相關(guān)業(yè)務(wù),后文也將會(huì)將基于筆者所在公司的業(yè)務(wù)詳細(xì)闡述CRM各模塊,感興趣的朋友快來看看吧
    2021-11-11

最新評(píng)論

林口县| 桐城市| 固安县| 韩城市| 泗洪县| 黑河市| 依兰县| 宣威市| 驻马店市| 巫溪县| 淄博市| 孙吴县| 阿克陶县| 翁源县| 新民市| 莱芜市| 建瓯市| 偏关县| 光山县| 佛坪县| 界首市| 门源| 平凉市| 翼城县| 修水县| 东明县| 苍梧县| 巫山县| 革吉县| 东乌| 普兰店市| 双峰县| 儋州市| 巴彦淖尔市| 天津市| 通州区| 梅河口市| 永安市| 九龙城区| 介休市| 公主岭市|