Here’s a scenario — a user visits your site for the first time and logs in, then comes back the next day and has to log in again. So there are features like “Remember me” to make it easier for users to use, but one thing is self-evident, that is, the “prolonged” authentication status has long been beyond the scope of users’ original needs. This means that they can close the browser, and then shut down the computer, the next week or next month, and even more will come back later, as long as the interval time not too far, the site will know who is who, and, as always, to provide all of the same functions and services, and for a long time before they leave.

Remember my fundamentals

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/1/17/161049fa614ae478~tplv-t2oaga2asx-image.image

  1. Called after the user is successfully authenticatedRemeberMeServiceGenerated based on the user nameTokenbyTokenRepositoryWrite to the database, also willTokenWrite to the browserCookieIn the
  2. After the service is restarted, the user will log in to the system againRememberMeAuthenticationFilterInterception, fromCookieReads theTokenInformation, andpersistent_loginsThe table matches to determine whether the remember me function is used. The most ofUserDetailsServiceQuerying User Information

Remember me to achieve

  1. createpersistent_loginstable
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null);
Copy the code
  1. Add the Remember me check item to the landing page (Name must be remeber-me)
<input name="remember-me" type="checkbox">Next Automatic LoginCopy the code
  1. Configuration MerryyouSecurityConfig
http.
......
                .and()
                .rememberMe()
                .tokenRepository(persistentTokenRepository())// Set the Repository for the action table
                .tokenValiditySeconds(securityProperties.getRememberMeSeconds())// Set remember my time
                .userDetailsService(userDetailsService)/ / set the userDetailsService
                .and()
	......
Copy the code

Results the following

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/1/17/161049fab609ee1f~tplv-t2oaga2asx-image.image

Source code analysis

For the first time login

AbstractAuthenticationProcessingFilter#successfulAuthentication
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
			throws IOException, ServletException {

		if (logger.isDebugEnabled()) {
			logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
					+ authResult);
		}
		//# 1. Put the authenticated Authentication into the SecurityContext
		SecurityContextHolder.getContext().setAuthentication(authResult);
		//# 2. Login successfully to call rememberMeServices
		rememberMeServices.loginSuccess(request, response, authResult);

		// Fire event
		if (this.eventPublisher ! =null) {
			eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
					authResult, this.getClass()));
		}

		successHandler.onAuthenticationSuccess(request, response, authResult);
	}
Copy the code
  1. Put the authenticated Authentication into the SecurityContext
  2. Login successfully invoked rememberMeServices
AbstractRememberMeServices#loginSuccess
private String parameter = DEFAULT_PARAMETER;//remember-me

public final void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
		// #1. Check whether remember me is checked
		if(! rememberMeRequested(request, parameter)) { logger.debug("Remember-me login not requested.");
			return;
		}

		onLoginSuccess(request, response, successfulAuthentication);
	}
Copy the code
  1. Check whether remember me is checked
PersistentTokenBasedRememberMeServices#onLoginSuccess
protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
		//#1. Get the username
		String username = successfulAuthentication.getName();

		logger.debug("Creating new persistent login for user " + username);
		/ / # 2. Create a Token
		PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(
				username, generateSeriesData(), generateTokenData(), new Date());
		try {
			//#3. Store the database
			tokenRepository.createNewToken(persistentToken);
			//#4. Write to the browser Cookie
			addCookie(persistentToken, request, response);
		}
		catch (Exception e) {
			logger.error("Failed to save persistent token ", e); }}Copy the code
  1. Obtaining a user name
  2. Create a Token
  3. Storage capital database
  4. Write to a browser Cookie

Second login Remember-me

RememberMeAuthenticationFilter#doFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		//#1. Check that there is no Authentication in SecurityContext
		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			/ / # 2. From cookies return to RememberMeAuthenticationToken query user information
			Authentication rememberMeAuth = rememberMeServices.autoLogin(request,
					response);

			if(rememberMeAuth ! =null) {
				// Attempt authenticaton via AuthenticationManager
				try {
					//#3. If not empty, authenticationManager authenticates
					rememberMeAuth = authenticationManager.authenticate(rememberMeAuth);

					// Store to SecurityContextHolderSecurityContextHolder.getContext().setAuthentication(rememberMeAuth); onSuccessfulAuthentication(request, response, rememberMeAuth); .Copy the code
  1. Check that there is no Authentication in the SecurityContext
  2. From cookies return to RememberMeAuthenticationToken query user information
  3. If not empty, authenticationManager authenticates it
AbstractRememberMeServices#autoLogin
public final Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
			/ / # 1. Get a Cookie
		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 {
			/ / # 2. Analytical cookies
			String[] cookieTokens = decodeCookie(rememberMeCookie);
			//#3
			user = processAutoLoginCookie(cookieTokens, request, response);
			//#4. Check user credentials
			userDetailsChecker.check(user);

			logger.debug("Remember-me cookie accepted");
			/ / # 5. Return the Authentication
			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 (InvalidCookieException invalidCookie) {
			logger.debug("Invalid remember-me cookie: " + invalidCookie.getMessage());
		}
		catch (AccountStatusException statusInvalid) {
			logger.debug("Invalid UserDetails: " + statusInvalid.getMessage());
		}
		catch (RememberMeAuthenticationException e) {
			logger.debug(e.getMessage());
		}

		cancelCookie(request, response);
		return null;
	}
Copy the code
  1. To get a Cookie
  2. Parsing the Cookie
  3. Obtaining user credentials
  4. Checking user credentials

The code download

Download it from my Github, github.com/longfeizhen…