【问题标题】:Spring security token persistence storage not workingSpring安全令牌持久性存储不起作用
【发布时间】:2016-05-16 11:36:48
【问题描述】:

问题在于,除了记住我的逻辑之外,登录和所有事情都运行良好。未设置 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)
);

【问题讨论】:

    标签: spring spring-mvc spring-security spring-boot


    【解决方案1】:

    我已经重现了同样的问题。使用调试,我检查了 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标签,所以我无法调用onLoginSuccess()方法并陷入了if而不是else的块中。

    标记标志后,我能够持久化令牌和 cookie。

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

    【讨论】:

      【解决方案2】:

      Spring Security 带有两个 PersistentTokenRepository 实现: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);
          }
      
      }
      

      【讨论】:

      • 您的回答无关紧要。我遇到了同样的问题,问题不仅仅是将令牌数据插入数据库,remember-me cookie 也没有在客户端(浏览器)中创建。所以我认为这不仅仅是将令牌数据写入数据库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-08
      • 2021-02-21
      • 2015-06-20
      • 2011-07-03
      • 1970-01-01
      • 2016-08-07
      • 2019-03-05
      相关资源
      最近更新 更多