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

Spring Security Remember me使用及原理詳解

 更新時間:2019年09月20日 14:22:16   作者:僅此而已-遠(yuǎn)方  
這篇文章主要介紹了Spring Security Remember me使用及原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

Remember me功能就是勾選"記住我"后,一次登錄,后面在有效期內(nèi)免登錄。

先看具體配置:

pom文件:

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

Security的配置:

@Autowired
  private UserDetailsService myUserDetailServiceImpl; // 用戶信息服務(wù)
  @Autowired
  private DataSource dataSource; // 數(shù)據(jù)源
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // formLogin()是默認(rèn)的登錄表單頁,如果不配置 loginPage(url),則使用 spring security
    // 默認(rèn)的登錄頁,如果配置了 loginPage()則使用自定義的登錄頁
    http.formLogin() // 表單登錄
        .loginPage(SecurityConst.AUTH_REQUIRE)
        .loginProcessingUrl(SecurityConst.AUTH_FORM) // 登錄請求攔截的url,也就是form表單提交時指定的action
        .successHandler(loginSuccessHandler)
        .failureHandler(loginFailureHandler)
        .and()
      .rememberMe()
        .userDetailsService(myUserDetailServiceImpl) // 設(shè)置userDetailsService
        .tokenRepository(persistentTokenRepository()) // 設(shè)置數(shù)據(jù)訪問層
        .tokenValiditySeconds(60 * 60) // 記住我的時間(秒)
        .and()
      .authorizeRequests() // 對請求授權(quán)
        .antMatchers(SecurityConst.AUTH_REQUIRE, securityProperty.getBrowser().getLoginPage()).permitAll() // 允許所有人訪問login.html和自定義的登錄頁
        .anyRequest() // 任何請求
        .authenticated()// 需要身份認(rèn)證
        .and()
      .csrf().disable() // 關(guān)閉跨站偽造
    ;
  }
  /**
   * 持久化token
   * 
   * Security中,默認(rèn)是使用PersistentTokenRepository的子類InMemoryTokenRepositoryImpl,將token放在內(nèi)存中
   * 如果使用JdbcTokenRepositoryImpl,會創(chuàng)建表persistent_logins,將token持久化到數(shù)據(jù)庫
   */
  @Bean
  public PersistentTokenRepository persistentTokenRepository() {
    JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
    tokenRepository.setDataSource(dataSource); // 設(shè)置數(shù)據(jù)源
//    tokenRepository.setCreateTableOnStartup(true); // 啟動創(chuàng)建表,創(chuàng)建成功后注釋掉
    return tokenRepository;
  }

上面的myUserDetailServiceImpl是自己實現(xiàn)的UserDetailsService接口,dataSource會自動讀取數(shù)據(jù)庫配置。過期時間設(shè)置的3600秒,即一個小時

在登錄頁面加一行(name必須是remeber-me):

"記住我"基本原理:

1、第一次發(fā)送認(rèn)證請求,會被UsernamePasswordAuthenticationFilter攔截,然后身份認(rèn)證。

認(rèn)證成功后,在AbstracAuthenticationProcessingFilter中,有個RememberMeServices接口。

該接口默認(rèn)實現(xiàn)類是NullRememberMeServices,這里會調(diào)用另一個實現(xiàn)抽象類AbstractRememberMeServices

// ...
  private RememberMeServices rememberMeServices = new NullRememberMeServices();
  protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
      Authentication authResult) throws IOException, ServletException {
    // ...
    SecurityContextHolder.getContext().setAuthentication(authResult);
    // 登錄成功后,調(diào)用RememberMeServices保存Token相關(guān)信息
    rememberMeServices.loginSuccess(request, response, authResult);
    // ...
  }

2、調(diào)用AbstractRememberMeServices的loginSuccess方法。

可以看到如果request中name為"remember-me"為true時,才會調(diào)用下面的onLoginSuccess()方法。這也是為什么上面登錄頁中的表單,name必須是"remember-me"的原因:

3、在Security中配置了rememberMe()之后, 會由PersistentTokenBasedRememberMeServices去實現(xiàn)父類AbstractRememberMeServices中的抽象方法。

在PersistentTokenBasedRememberMeServices中,有一個PersistentTokenRepository,會生成一個Token,并將這個Token寫到cookie里面返回瀏覽器。PersistentTokenRepository的默認(rèn)實現(xiàn)類是InMemoryTokenRepositoryImpl,該默認(rèn)實現(xiàn)類會將token保存到內(nèi)存中。這里我們配置了它的另一個實現(xiàn)類JdbcTokenRepositoryImpl,該類會將Token持久化到數(shù)據(jù)庫中

// ...

  private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl();
  protected void onLoginSuccess(HttpServletRequest request,
      HttpServletResponse response, Authentication successfulAuthentication) {
    String username = successfulAuthentication.getName();

    logger.debug("Creating new persistent login for user " + username);

    // 創(chuàng)建一個PersistentRememberMeToken
    PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(
        username, generateSeriesData(), generateTokenData(), new Date());
    try {
      // 保存Token
      tokenRepository.createNewToken(persistentToken);
      // 將Token寫到Cookie中
      addCookie(persistentToken, request, response);
    }
    catch (Exception e) {
      logger.error("Failed to save persistent token ", e);
    }
  }

4、JdbcTokenRepositoryImpl將Token持久化到數(shù)據(jù)庫

/** The default SQL used by <tt>createNewToken</tt> */
  public static final String DEF_INSERT_TOKEN_SQL = "insert into persistent_logins (username, series, token, last_used) values(?,?,?,?)";

  public void createNewToken(PersistentRememberMeToken token) {
    getJdbcTemplate().update(insertTokenSql, token.getUsername(), token.getSeries(),
        token.getTokenValue(), token.getDate());
  }

查看數(shù)據(jù)庫,可以看到往persistent_logins 中插入了一條數(shù)據(jù):

5、重啟服務(wù),發(fā)送第二次認(rèn)證請求,只會攜帶Cookie。

所以直接會被RememberMeAuthenticationFilter攔截,并且此時內(nèi)存中沒有認(rèn)證信息。

可以看到,此時的RememberMeServices是由PersistentTokenBasedRememberMeServices實現(xiàn)

6、在PersistentTokenBasedRememberMeServices中,調(diào)用processAutoLoginCookie方法,獲取用戶相關(guān)信息

protected UserDetails processAutoLoginCookie(String[] cookieTokens,
      HttpServletRequest request, HttpServletResponse response) {

    if (cookieTokens.length != 2) {
      throw new InvalidCookieException("Cookie token did not contain " + 2
          + " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
    }

    // 從Cookie中獲取Series和Token
    final String presentedSeries = cookieTokens[0];
    final String presentedToken = cookieTokens[1]; 

    //在數(shù)據(jù)庫中,通過Series查詢PersistentRememberMeToken
    PersistentRememberMeToken token = tokenRepository
        .getTokenForSeries(presentedSeries);

    if (token == null) {
      throw new RememberMeAuthenticationException(
          "No persistent token found for series id: " + presentedSeries);
    }

    // 校驗數(shù)據(jù)庫中Token和Cookie中的Token是否相同
    if (!presentedToken.equals(token.getTokenValue())) {
      tokenRepository.removeUserTokens(token.getUsername());

      throw new CookieTheftException(
          messages.getMessage(
              "PersistentTokenBasedRememberMeServices.cookieStolen",
              "Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack."));
    }

    // 判斷Token是否超時
    if (token.getDate().getTime() + getTokenValiditySeconds() * 1000L < System
        .currentTimeMillis()) {
      throw new RememberMeAuthenticationException("Remember-me login has expired");
    }

    if (logger.isDebugEnabled()) {
      logger.debug("Refreshing persistent login token for user '"
          + token.getUsername() + "', series '" + token.getSeries() + "'");
    }
    
    // 創(chuàng)建一個新的PersistentRememberMeToken
    PersistentRememberMeToken newToken = new PersistentRememberMeToken(
        token.getUsername(), token.getSeries(), generateTokenData(), new Date());

    try {
      //更新數(shù)據(jù)庫中Token
      tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(),
          newToken.getDate());
      //重新寫到Cookie
      addCookie(newToken, request, response);
    }
    catch (Exception e) {
      logger.error("Failed to update token: ", e);
      throw new RememberMeAuthenticationException(
          "Autologin failed due to data access problem");
    }
    //調(diào)用UserDetailsService獲取用戶信息
    return getUserDetailsService().loadUserByUsername(token.getUsername());
  }

7、獲取用戶相關(guān)信息后,再調(diào)用AuthenticationManager去認(rèn)證授權(quán)

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java如果通過jdbc操作連接oracle數(shù)據(jù)庫

    Java如果通過jdbc操作連接oracle數(shù)據(jù)庫

    這篇文章主要介紹了Java如果通過jdbc操作連接oracle數(shù)據(jù)庫,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot攔截器實現(xiàn)登錄攔截的示例代碼

    SpringBoot攔截器實現(xiàn)登錄攔截的示例代碼

    本文主要介紹了SpringBoot攔截器實現(xiàn)登錄攔截,文中根據(jù)實例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • springboot整合JavaCV實現(xiàn)視頻截取第N幀并保存圖片

    springboot整合JavaCV實現(xiàn)視頻截取第N幀并保存圖片

    這篇文章主要為大家詳細(xì)介紹了springboot如何整合JavaCV實現(xiàn)視頻截取第N幀并保存為圖片,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-08-08
  • Java中的@PreAuthorize注解源碼解析

    Java中的@PreAuthorize注解源碼解析

    這篇文章主要介紹了Java中的@PreAuthorize注解源碼解析,@PreAuthorize注解會在方法執(zhí)行前進(jìn)行權(quán)限驗證,支持Spring?EL表達(dá)式,它是基于方法注解的權(quán)限解決方案,需要的朋友可以參考下
    2023-10-10
  • 解決SpringBoot 測試類無法自動注入@Autowired的問題

    解決SpringBoot 測試類無法自動注入@Autowired的問題

    這篇文章主要介紹了解決SpringBoot 測試類無法自動注入@Autowired的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • mybatis-plus分頁查詢的實現(xiàn)實例

    mybatis-plus分頁查詢的實現(xiàn)實例

    頁查詢是一項常用的數(shù)據(jù)庫查詢方法,本文主要介紹了mybatis-plus分頁查詢的實現(xiàn)實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • 深度剖析Java成員變量、局部變量和靜態(tài)變量的創(chuàng)建和回收時機(jī)

    深度剖析Java成員變量、局部變量和靜態(tài)變量的創(chuàng)建和回收時機(jī)

    這篇文章主要介紹了深度剖析Java成員變量、局部變量和靜態(tài)變量的創(chuàng)建和回收時機(jī),成員變量是定義在類中的變量,每個類的實例都會擁有自己的成員變量。它們的生命周期與對象的創(chuàng)建和銷毀相對應(yīng),下面我將詳細(xì)介紹它們的特點和生命周期,需要的朋友可以參考下
    2023-07-07
  • java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計

    java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計

    這篇文章主要為大家詳細(xì)介紹了java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Java實現(xiàn)優(yōu)先隊列式廣度優(yōu)先搜索算法的示例代碼

    Java實現(xiàn)優(yōu)先隊列式廣度優(yōu)先搜索算法的示例代碼

    這篇文章主要為大家詳細(xì)介紹了Java如何實現(xiàn)優(yōu)先隊列式廣度優(yōu)先搜索算法,文中通過一個示例帶大家具體了解了實現(xiàn)的方法,需要的可以參考一下
    2022-08-08
  • JAVA 開發(fā)之用靜態(tài)方法返回類名的實例詳解

    JAVA 開發(fā)之用靜態(tài)方法返回類名的實例詳解

    這篇文章主要介紹了JAVA 開發(fā)之用靜態(tài)方法返回類名的實例詳解的相關(guān)資料,這里主要說明使用異常來得到類名,希望能幫助到大家,需要的朋友可以參考下
    2017-08-08

最新評論

和林格尔县| 淳化县| 北安市| 溧阳市| 万荣县| 石狮市| 涡阳县| 斗六市| 五峰| 肃宁县| 巴林左旗| 建始县| 阿瓦提县| 息烽县| 宝应县| 九台市| 澄江县| 永和县| 阜阳市| 陇南市| 珲春市| 凌源市| 金华市| 德令哈市| 牙克石市| 分宜县| 桐庐县| 石狮市| 和平县| 鄂尔多斯市| 桃园县| 德庆县| 甘南县| 林周县| 宁德市| 古浪县| 章丘市| 文登市| 金堂县| 理塘县| 平武县|