Spring Security Remember-me配置

2019-03-26  本文已影响0人  LoWang

scio

https://github.com/rench/scio

Remember Me 记住我

介绍

实现

  1. TokenBasedRememberMeServices 生成cookie中包含用户名的token,每次请求从带入的cookie中获取username,然后根据username从userDetailsService中获取数据生成token进行比较。生成的方式如下:
username + ":" + expiryTime + ":"
        + Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)
  1. PersistentTokenBasedRememberMeServices 生成的cookie中不包含用户名,包含series和token,并存储于数据库中,同时,存储的数据中还包含了用户名和token最近访问时间。每次请求根据带入cookie中的series和token,查询数据库中的数据进行token比对,同时调用userDetailsService进行用户的状态校验。

PersistentTokenRepositoryPersistentTokenBasedRememberMeServices中存储实现。默认是InMemoryTokenRepositoryImpl,框架中附带了JdbcTokenRepositoryImpl实现,可以根据自己的实际情况增加实现,比如redis等。

  1. 基于TokenBasedRememberMeServices,可以进行扩展,对cookie进行加密等操作,默认的cookie(mp1:1554694664576:801c3f24109a468dfbeb7cf09cac0531)没有加密用户名,只是进行base64编码,可能存在泄漏的风险。

配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ScioRememberMeSecurityConfig extends WebSecurityConfigurerAdapter {
  private static final String SECRET = "scio@2019";
  @Autowired private UserDetailsService scioUserDetailsService;
  /**
   * password encoder
   *
   * @return
   */
  @Bean
  public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
  }

  /**
   * RememberMeAuthenticationProvider.
   *
   * @return
   */
  @Bean
  public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
    return new RememberMeAuthenticationProvider(SECRET);
  }

  /**
   * TokenBasedRememberMeServices.
   *
   * @return
   */
  @Bean("tokenBaseRememberMeServices")
  public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
    TokenBasedRememberMeServices rememberMeServices =
        new TokenBasedRememberMeServices(SECRET, scioUserDetailsService);
    rememberMeServices.setAlwaysRemember(false);
    rememberMeServices.setCookieName("remember-me");
    rememberMeServices.setTokenValiditySeconds(AbstractRememberMeServices.TWO_WEEKS_S);
    return rememberMeServices;
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(scioUserDetailsService).passwordEncoder(passwordEncoder());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // http.antMatcher("/api/**");
    // .antMatchers("/api/login", "/api/logout")
    http.csrf()
        .disable()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
    // permit login
    http.formLogin()
        .permitAll()
        .defaultSuccessUrl("/info")
        .and()
        .authorizeRequests()
        .anyRequest()
        .authenticated();
    http.rememberMe()
        // tokenBased, store token and user name in token data.
        .rememberMeServices(tokenBasedRememberMeServices())
        // .tokenRepository(new InMemoryTokenRepositoryImpl())
        // persistent serials/token, invalidate after delete from token store
        .and()
        .authenticationProvider(rememberMeAuthenticationProvider());
    http.headers().cacheControl();
  }
}
/**
 * mock scio users
 *
 * @author Wang.ch
 * @date 2019-03-25 09:05:21
 */
@Configuration
public class ScioUserDetailsService implements UserDetailsService {
  /** mock users */
  private Map<String, String> users = new HashMap<>();

  public ScioUserDetailsService() {
    users.put("mp1", "{noop}mp1");
    users.put("mp2", "{noop}mp2");
  }

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    if (users.containsKey(username)) {
      String noopPwd = users.get(username);
      User u = new User(username, noopPwd, Arrays.asList(new SimpleGrantedAuthority("USER")));
      return u;
    } else {
      throw new UsernameNotFoundException("user not found");
    }
  }
}

使用

上一篇 下一篇

猜你喜欢

热点阅读