Spring MVC Spring安全令牌持久性存储不工作

vfh0ocws  于 2023-01-13  发布在  Spring
关注(0)|答案(3)|浏览(213)

问题是登录和所有的东西都工作得很好,除了记住我的逻辑。cookie没有设置,也没有在数据库中插入行。
这是安全配置类。

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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * Spring security configurations.
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // Authorize all requests
                .authorizeRequests()
                    // Allow only admins to access the administration pages
                    .antMatchers("/admin/**").access("hasRole('ADMIN')")
                    // Allow any one to access the register and the main pages only alongside
                    // the resources files that contains css and javascript files
                    .antMatchers("/resources/**", "/register", "/").permitAll()
                    // Authenticate any other request
                    .anyRequest().authenticated()
                    .and()
                // Set up the login form.
                .formLogin()
                    //.successHandler(successHandler())
                    .loginPage("/login")
                    .usernameParameter("email").passwordParameter("password")
                    .permitAll()
                    .and()
                // Enable remember me cookie and persistence storage
                .rememberMe()
                    // Database token repository
                    .tokenRepository(persistentTokenRepository())
                    // Valid for 20 days
                    .tokenValiditySeconds(20 * 24 * 60 * 60)
                    .rememberMeParameter("remember-me")
                    .and()
                // Log out handler
                .logout()
                    .permitAll()
                    .and()
                // Enable Cross-Site Request Forgery
                .csrf();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
        db.setDataSource(dataSource);
        return db;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // Provide database authentication and swl queries to fetch the user's data..
        auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("select email, password, enabled from users where email=?")
                .authoritiesByUsernameQuery("select us.email, ur.role from users us, " +
                        " roles ur where us.role_id=ur.id and us.email=?");
    }
}

这是令牌持久性的数据库表

CREATE TABLE persistent_logins (
    username VARCHAR(254) NOT NULL,
    series VARCHAR(64) NOT NULL,
    token VARCHAR(64) NOT NULL,
    last_used TIMESTAMP NOT NULL,
    PRIMARY KEY (series)
);
wnrlj8wa

wnrlj8wa1#

Spring Security附带了2个持久性令牌库实现:JdbcTokenRepositoryImpl和InMemoryTokenRepositoryImpl。我在我的应用程序中使用Hibernate,我使用Hibernate而不是JDBC创建了一个自定义实现。

@Repository("tokenRepositoryDao")
@Transactional
public class HibernateTokenRepositoryImpl extends AbstractDao<String, PersistentLogin>
        implements PersistentTokenRepository {

    static final Logger logger = LoggerFactory.getLogger(HibernateTokenRepositoryImpl.class);

    @Override
    public void createNewToken(PersistentRememberMeToken token) {
        logger.info("Creating Token for user : {}", token.getUsername());
        PersistentLogin persistentLogin = new PersistentLogin();
        persistentLogin.setUsername(token.getUsername());
        persistentLogin.setSeries(token.getSeries());
        persistentLogin.setToken(token.getTokenValue());
        persistentLogin.setLast_used(token.getDate());
        persist(persistentLogin);

    }

    @Override
    public PersistentRememberMeToken getTokenForSeries(String seriesId) {
        logger.info("Fetch Token if any for seriesId : {}", seriesId);
        try {
            Criteria crit = createEntityCriteria();
            crit.add(Restrictions.eq("series", seriesId));
            PersistentLogin persistentLogin = (PersistentLogin) crit.uniqueResult();

            return new PersistentRememberMeToken(persistentLogin.getUsername(), persistentLogin.getSeries(),
                    persistentLogin.getToken(), persistentLogin.getLast_used());
        } catch (Exception e) {
            logger.info("Token not found...");
            return null;
        }
    }

    @Override
    public void removeUserTokens(String username) {
        logger.info("Removing Token if any for user : {}", username);
        Criteria crit = createEntityCriteria();
        crit.add(Restrictions.eq("username", username));
        PersistentLogin persistentLogin = (PersistentLogin) crit.uniqueResult();
        if (persistentLogin != null) {
            logger.info("rememberMe was selected");
            delete(persistentLogin);
        }

    }

    @Override
    public void updateToken(String seriesId, String tokenValue, Date lastUsed) {
        logger.info("Updating Token for seriesId : {}", seriesId);
        PersistentLogin persistentLogin = getByKey(seriesId);
        persistentLogin.setToken(tokenValue);
        persistentLogin.setLast_used(lastUsed);
        update(persistentLogin);
    }

}
np8igboo

np8igboo2#

我重现了同样的问题。我使用debug检查了AbstractRememberMeServices类的loginSuccess()方法。
内在逻辑是这样的:

public final void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
    if (!this.rememberMeRequested(request, this.parameter)) {
        this.logger.debug("Remember-me login not requested.");
    } else {
        this.onLoginSuccess(request, response, successfulAuthentication);
    }
}

结果是,当用户登录时,我没有被标记为Remember Me tag,因此我无法调用onLoginSuccess()方法,并陷入if而不是else块。
标记标记之后,我就能够持久化令牌和cookie。

**注意:**逻辑可以从@FuSsA提到的答案中得到。

tquggr8v

tquggr8v3#

对,所以实际上,cookie是写在登录成功处理程序中的,所以DB持久性错误可能会导致cookie写不成功。我的问题是ms sql中持久性表中的数据类型on date:

CREATE TABLE [dbo].[persistent_logins](
--[id] [bigint] IDENTITY(1,1) NOT NULL,
[username] [varchar](64) NOT NULL,
[series] [varchar](64) NOT NULL,
[token] [varchar](64) NOT NULL,
[last_used] [datetime] NOT NULL default CURRENT_TIMESTAMP);

从那里,安全配置是:

.rememberMe()
  // Valid for 20 days
  .tokenValiditySeconds(20 * 24 * 60 * 60)
   .rememberMeParameter("remember-me")
   .key("yourPrivateKeyOfChoice")
   .tokenRepository(persistentTokenRepository())             
   .rememberMeServices(rememberMeServices())
...
@Bean
public RememberMeServices rememberMeServices() {
    CustomRememberMeServices rememberMeServices = new 
    CustomRememberMeServices("againThePrivateKey", 
            userDetailsService, persistentTokenRepository());
    return rememberMeServices;
  }
@Autowired
@Qualifier("dataSourceEwoForSap")
DriverManagerDataSource dataSource;

@Bean
public PersistentTokenRepository persistentTokenRepository() {
    JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
    db.setCreateTableOnStartup(false);
    db.setDataSource(dataSource);
    return db;

}
......那么习惯记住我

public CustomRememberMeServices(String key, UserDetailsService userDetailsService, PersistentTokenRepository tokenRepository) {
    super(key, userDetailsService, tokenRepository);
    this.tokenRepository = tokenRepository;
    this.key = key;
}

      
@Override
protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
    String username = ((User) successfulAuthentication.getPrincipal()).getEmail();
    logger.debug("Creating new persistent login for user " + username);
    PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(username, generateSeriesData(), generateTokenData(), new Date());
    try {
        tokenRepository.createNewToken(persistentToken);
        addCookie(persistentToken, request, response);
    } catch (Exception e) {
        logger.error("Failed to save persistent token ", e);
    }
}

相关问题