Spring Security 记住我功能基本原理,实现及源码追踪

版权声明:士,不可以不弘毅,任重而道远 https://blog.csdn.net/superbeyone/article/details/84728370


Spring Security 记住我功能基本原理,实现及源码追踪

1. 流程分析

在这里插入图片描述

2. 过滤器链

在这里插入图片描述

3. 代码实现

3.1 页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h2>标准登录页面</h2>
<h3>表单登录</h3>
<form action="/authentication/form" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username" id="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" id="password"></td>
        </tr>
        <tr>
            <td>图形验证码</td>
            <td><input type="text" name="imageCode" id="imageCode">
                <img src="/code/image" alt="">
            </td>
        </tr>
        <tr>
            <td colspan="2"><input type="checkbox" name="remember-me" id="remember_me" checked/>记住我</td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">提交</button>
            </td>
        </tr>
    </table>

</form>
</body>
</html>

3.2 后台

import com.tdt.security.browser.authentication.TdtAuthenticationFailureHandler;
import com.tdt.security.browser.authentication.TdtAuthenticationSuccessHandler;
import com.tdt.security.properties.SecurityProperties;
import com.tdt.security.validate.code.ValidateCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;


/**
 * @Project: tdt-security
 * @ClassName: BrowserSecurityConfig
 * @Description: 浏览器配置类
 * @Author: Mr.superbeyone
 * @Create: 2018-11-28 16:44
 **/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SecurityProperties securityProperties;

    @Autowired
    TdtAuthenticationSuccessHandler tdtAuthenticationSuccessHandler;

    @Autowired
    TdtAuthenticationFailureHandler tdtAuthenticationFailureHandler;

    @Autowired
    DataSource dataSource;

    @Autowired
    UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder BCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

//记住我功能 start 
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
//        tokenRepository.setCreateTableOnStartup(true);//第一次启动时放开,会自动生成persistent_logins表
        //"create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, "
        //			+ "token varchar(64) not null, last_used timestamp not null)"
        return tokenRepository;
    }
//记住我功能 end

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
        validateCodeFilter.setAuthenticationFailureHandler(tdtAuthenticationFailureHandler);
        validateCodeFilter.setSecurityProperties(securityProperties);
        validateCodeFilter.afterPropertiesSet();

        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .formLogin()   //想用默认的HttpBasic登录使用    http.httpBasic()
                .loginPage("/authentication/require")
                .loginProcessingUrl("/authentication/form")
                .successHandler(tdtAuthenticationSuccessHandler)
                .failureHandler(tdtAuthenticationFailureHandler)
                .and() 
                .rememberMe()//配置记住我
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//参数为整形数值,在此只是封装了一下
                .userDetailsService(userDetailsService)
                .and()
                .authorizeRequests()//下面的配置都是授权配置
                .antMatchers("/authentication/require",
                        securityProperties.getBrowser().getLoginPage(),
                        "/code/image")
                .permitAll()
                .anyRequest()//任何请求
                .authenticated()//都需要身份认证
                .and()
                .csrf().disable();//关闭跨站请求防护
    }
}

注:展示的代码只是实现思想,完成代码结构,移步GitHub 源码地址

4. 源码追踪

4.1 第一次登录

  • UsernamePasswordAuthenticationFilter
    在这里插入图片描述
  • AbstractAuthenticationProcessingFilter
    在这里插入图片描述
  • PersistentTokenBasedRememberMeServices
    在这里插入图片描述

4.2 记住我之后,第二次登录

  • RememberMeAuthenticationFilter
    在这里插入图片描述
  • PersistentTokenBasedRememberMeServices
  • 经过一系列检查之后
    在这里插入图片描述
  • RememberMeAuthenticationFilter在这里插入图片描述
    github 源码地址

猜你喜欢

转载自blog.csdn.net/superbeyone/article/details/84728370