【Spring Security系列】Spring Security自动登录

1.为什么需要自动登录

当我们在某个网站上注册账号时,网站会对我们设置的登录密码提出要求。例如,有的网站要求使用固定位数的纯数字密码,有的网站则强制要求用户使用英文+数字组合成的密码,甚至要求加一些特殊符号来组成密码。总体而言,设定一个密码并不困难,真正的困难总是在下次登录时才会遇到。要么想不出网站要求的密码格式是什么,要么还原不了设置密码时的思维状态。总之,在几次尝试登录失败之后,大部分人会选择找回密码,从而再次陷入如何设置密码的循环里。为了尽可能减少用户重新登录的频率,在系统开发之初就需要考虑加入可以提升用户登录体验的功能。自动登录便是这样一个会给用户带来便利,同时也会给用户带来风险的体验性功能。自动登录是将用户的登录信息保存在用户浏览器的cookie中,当用户下次访问时,自动实现校验并建立登录态的一种机制。

Spring Security提供了两种非常好的令牌:

  • 用散列算法加密用户必要的登录信息并生成令牌。
  • 数据库等持久性数据存储机制用的持久化令牌。

散列算法在Spring Security中是通过加密几个关键信息实现的。

 

2.实现自动登录

(1)散列加密方案

在Spring Security中加入自动登录的功能非常简单。

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService userDetailService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/api/**").hasRole("ADMIN")
                .antMatchers("/user/api/**").hasRole("USER")
                .antMatchers("/app/api/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
            .formLogin()
                .and()
            .rememberMe().userDetailsService(userDetailService);
    }
}

前提是已经实现了一个 UserDetailsService。重启服务后访问受限 API,这次在表单登录页中多了一个可选框。

勾选“Remember me on this computer”可选框(简写为Remember-me),按照正常的流程登录,并在开发者工具中查看浏览器cookie,可以看到除JSESSIONID外多了一个值

 

这就是Spring Security默认自动登录的cookie字段。在不配置的情况下,过期时间是两个星期。

public abstract class AbstractRememberMeServices implements RememberMeServices,
		InitializingBean, LogoutHandler {
	// ~ Static fields/initializers
	// =====================================================================================

	public static final String SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY = "remember-me";
	public static final String DEFAULT_PARAMETER = "remember-me";
	public static final int TWO_WEEKS_S = 1209600;

	private static final String DELIMITER = ":";

	// ~ Instance fields
	// ================================================================================================
	protected final Log logger = LogFactory.getLog(getClass());

	protected final MessageSourceAccessor messages = SpringSecurityMessageSource
			.getAccessor();

	private UserDetailsService userDetailsService;
	private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
	private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();

	private String cookieName = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
	private String cookieDomain;
	private String parameter = DEFAULT_PARAMETER;
	private boolean alwaysRemember;
	private String key;
	private int tokenValiditySeconds = TWO_WEEKS_S;
	private Boolean useSecureCookie = null;
	private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();

	protected AbstractRememberMeServices(String key, UserDetailsService userDetailsService) {
		Assert.hasLength(key, "key cannot be empty or null");
		Assert.notNull(userDetailsService, "UserDetailsService cannot be null");
		this.key = key;
		this.userDetailsService = userDetailsService;
	}

	@Override
	public void afterPropertiesSet() {
		Assert.hasLength(key, "key cannot be empty or null");
		Assert.notNull(userDetailsService, "A UserDetailsService is required");
	}

	/**
	 * Template implementation which locates the Spring Security cookie, decodes it into a
	 * delimited array of tokens and submits it to subclasses for processing via the
	 * <tt>processAutoLoginCookie</tt> method.
	 * <p>
	 * The returned username is then used to load the UserDetails object for the user,
	 * which in turn is used to create a valid authentication token.
	 */
	@Override
	public final Authentication autoLogin(HttpServletRequest request,
			HttpServletResponse response) {
		String rememberMeCookie = extractRememberMeCookie(request);

		if (rememberMeCookie == null) {
			return null;
		}

		logger.debug("Remember-me cookie detected");

		if (rememberMeCookie.length() == 0) {
			logger.debug("Cookie was empty");
			cancelCookie(request, response);
			return null;
		}

		UserDetails user = null;

		try {
			String[] cookieTokens = decodeCookie(rememberMeCookie);
			user = processAutoLoginCookie(cookieTokens, request, response);
			userDetailsChecker.check(user);

			logger.debug("Remember-me cookie accepted");

			return createSuccessfulAuthentication(request, user);
		}
		catch (CookieTheftException cte) {
			cancelCookie(request, response);
			throw cte;
		}
		catch (UsernameNotFoundException noUser) {
			logger.debug("Remember-me login was valid but corresponding user not found.",
					noUser);
		}
		catch (InvalidCookieExc
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Spring Security自动登录功能,你可以按照以下步骤进行操作: 1. 确保你已经将Spring Security添加到你的项目中,并配置好了基本的安全设置。 2. 创建一个实现了`UserDetailsService`接口的类,用于从数据库或其他数据源中加载用户信息。该接口中的`loadUserByUsername`方法根据用户名返回一个`UserDetails`对象,其中包含了用户的信息和权限。 3. 在Spring Security的配置文件中,使用`rememberMe()`方法启用自动登录功能,并配置相关参数。例如: ```java @Override protected void configure(HttpSecurity http) throws Exception { http .rememberMe() .key("yourSecretKey") // 设置一个密钥,用于生成和验证令牌 .userDetailsService(userDetailsService); // 设置刚才创建的UserDetailsService实现类 } ``` 4. 在用户登录成功后,使用`RememberMeServices`接口提供的方法生成一个持久化的令牌,并将其发送给客户端。 ```java @Autowired private RememberMeServices rememberMeServices; @PostMapping("/login") public String login(HttpServletRequest request, HttpServletResponse response) { // 处理用户登录逻辑 // 生成一个持久化的令牌并发送给客户端 rememberMeServices.loginSuccess(request, response, authentication); } ``` 5. 在应用程序启动时,配置一个`PersistentTokenRepository`实现类来管理持久化令牌的存储和检索。你可以选择将令牌存储在数据库中或其他持久化存储器中。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... @Bean public PersistentTokenRepository persistentTokenRepository() { // 配置持久化令牌的存储和检索方式 // 例如,可以使用JdbcTokenRepositoryImpl将令牌存储在数据库中 JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl(); tokenRepository.setDataSource(dataSource); return tokenRepository; } } ``` 通过按照以上步骤进行配置,你就可以实现Spring Security自动登录功能了。当用户登录成功并选择“记住我”选项时,下次访问应用程序时就会自动使用持久化的令牌进行登录

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值