Spring Security's remomberme automatic login

Keywords: Spring Session Database

Automatic login is a mechanism that saves the user's login information in the cookie of the user's browser. When the user visits next time, it automatically realizes the verification and establishes the login state.
Spring Security provides two very good types of Tokens:

  • Hash algorithm encrypts user's necessary login information and generates token
  • Persistent token for persistent data storage mechanism such as database



Hash encryption scheme

Adding automatic login to Spring Security is simple:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/api/user/**").hasRole("user")  //User role access route at the beginning of / api/user /
                .antMatchers("/api/admin/**").hasRole("admin") //Admin role access routes beginning with / api/admin /
                .antMatchers("/api/public/**").permitAll()                 //Allow all routes with access to the beginning of / api/public /
                .and()
                .formLogin()
                .and()
                .rememberMe().userDetailsService(userDetailsService());      //Remember the password
    }


After restarting the service, access to the restricted API. This time, there is an optional box in the form login page:


Check the "Remember me on this computer" option box (abbreviated to remember me), log in according to the normal process, and view the browser cookie in the developer tool. You can see that there is an additional value in addition to JSESSIONID:


This is the cookie field that Spring Security automatically logs in by default. Without configuration, the expiration time is two weeks:

Spring Security will update this token after each successful form login. The specific processing method is in the source code:



RememberConfigurer:



Persistent token scheme

In the persistent token scheme, the core values are series and token, which are random strings hashed with MD5. The difference is that series is only updated when the user logs in again with a password, and the token is regenerated in each new session.
It solves the problem that one token can log in at the same time. Each session will trigger token change
New, that is, each token only supports single instance login.
Automatic login will not cause series change, and each automatic login needs to verify both series and token values at the same time
When the token is stolen before the automatic login is used, the system will refresh the token value after the illegal user passes the authentication. At this time, when the legal user
The token value has expired in the browser of. When the legal user uses automatic login, because the tokens corresponding to the series are different, the system
It can be inferred that the token may have been stolen for some processing. For example, clean up all autologon tokens for the user and notify the
The user may have been stolen, etc
Spring Security uses PersistentRememberMeToken to indicate a verification entity:







public class PersistentRememberMeToken {
    private final String username;
    private final String series;
    private final String tokenValue;
    private final Date date;

    public PersistentRememberMeToken(String username, String series, String tokenValue, Date date) {
        this.username = username;
        this.series = series;
        this.tokenValue = tokenValue;
        this.date = date;
    }

    public String getUsername() {
        return this.username;
    }

    public String getSeries() {
        return this.series;
    }

    public String getTokenValue() {
        return this.tokenValue;
    }

    public Date getDate() {
        return this.date;
    }
}

You need to use the persistent token scheme. You need to pass in an instance of persistenttokenreposition:

The persistent token reposition interface mainly involves the addition, deletion, query and modification of four interfaces:

Mypersistenttokenrepositorimpl enables us to implement the PersistentTokenRepository interface:

@Service
public class MyPersistentTokenRepositoryImpl implements PersistentTokenRepository {

    @Autowired
    private JPAPersistentTokenRepository  repository;

    @Override
    public void createNewToken(PersistentRememberMeToken persistentRememberMeToken) {
        MyPersistentToken myPersistentToken = new MyPersistentToken();
        myPersistentToken.setSeries(persistentRememberMeToken.getSeries());
        myPersistentToken.setUsername(persistentRememberMeToken.getUsername());
        myPersistentToken.setTokenValue(persistentRememberMeToken.getTokenValue());
        myPersistentToken.setUser_last(persistentRememberMeToken.getDate());
        repository.save(myPersistentToken);
    }

    @Override
    public void updateToken(String series, String tokenValue, Date lastUsed) {
        MyPersistentToken myPersistentToken = repository.findBySeries(series);
        myPersistentToken.setUser_last(lastUsed);
        myPersistentToken.setTokenValue(tokenValue);
        repository.save(myPersistentToken);
    }

    @Override
    public PersistentRememberMeToken getTokenForSeries(String series) {
        MyPersistentToken myPersistentToken = repository.findBySeries(series);
        PersistentRememberMeToken persistentRememberMeToken = new PersistentRememberMeToken(myPersistentToken.getUsername(), myPersistentToken.getSeries(), myPersistentToken.getTokenValue(), myPersistentToken.getUser_last());
        return persistentRememberMeToken;
    }

    @Override
    @Transactional
    public void removeUserTokens(String username) {
        repository.deleteByUsername(username);
    }
}
public interface JPAPersistentTokenRepository extends JpaRepository<MyPersistentToken,Long> {
    MyPersistentToken findBySeries(String series);
    void deleteByUsername(String username);
}
@Entity
@Table(name = "persistent_token")
public class MyPersistentToken {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private  String username;
    @Column(unique = true)
    private  String series;
    private  String tokenValue;
    private  Date user_last;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSeries() {
        return series;
    }

    public void setSeries(String series) {
        this.series = series;
    }

    public String getTokenValue() {
        return tokenValue;
    }

    public void setTokenValue(String tokenValue) {
        this.tokenValue = tokenValue;
    }

    public Date getUser_last() {
        return user_last;
    }

    public void setUser_last(Date user_last) {
        this.user_last = user_last;
    }
}

When the automatic login authentication, Spring Security obtains the user name, token and the last automatic login time through the series, confirms the identity of the token through the user name, finds out whether the token is valid by comparing the token, finds out whether the token has expired by the last automatic login time, and generates a new token after the complete verification.

Posted by exec1 on Sat, 27 Jun 2020 01:18:49 -0700