@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.rememberMe()
.and()
.csrf().disable();
}
- 只需要添加一个
.rememberMe()
即可,自动登录功能就成功添加进来了。
- JdbcTokenRepositoryImpl
CREATE TABLE `persistent_logins` (
`username` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
`series` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
`token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
// 用来保存令牌的处理类则是 PersistentRememberMeToken,该类的定义也很简洁命令:
public class PersistentRememberMeToken {
private final String username;
private final String series;
private final String tokenValue;
private final Date date;
//省略 getter
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(WebSecurity web) throws Exception {
//Ignore, public
web.ignoring().antMatchers("/public/**", "/static/**");
}
/**
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// CSRF禁用,因为不使用session
.csrf().disable();
// http.csrf().ignoringAntMatchers("/oauth/authorize", "/oauth/token", "/oauth/rest_token");
// 过滤请求
http.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/static/**").permitAll()
.antMatchers("/oauth/rest_token*").permitAll()
.antMatchers("/login*").permitAll()
.antMatchers("/user/**").hasAnyRole("ADMIN")
.antMatchers(HttpMethod.GET, "/login*").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/signin")
.failureUrl("/login?error=1")
.usernameParameter("oidc_user")
.passwordParameter("oidcPwd")
.and()
.rememberMe()
.key("javaboy")
.tokenRepository(jdbcTokenRepository())
.and()
.logout()
.logoutUrl("/signout")
.deleteCookies("JSESSIONID")
.logoutSuccessUrl("/")
.and()
.exceptionHandling();
http.authenticationProvider(authenticationProvider());
}
@Autowired
DataSource dataSource;
@Bean
JdbcTokenRepositoryImpl jdbcTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
/**
* 身份认证接口
*/
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return daoAuthenticationProvider;
}
/**
* BCrypt 加密
*
* @return PasswordEncoder
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
二次校验
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
@GetMapping("/rememberme")
public String rememberme() {
return "rememberme";
}
}
/hello
接口,只要认证后就可以访问,无论是通过用户名密码认证还是通过自动登录认证,只要认证了,就可以访问。/admin
接口,必须要用户名密码认证之后才能访问,如果用户是通过自动登录认证的,则必须重新输入用户名密码才能访问该接口。/rememberme
接口,必须是通过自动登录认证后才能访问,如果用户是通过用户名/密码认证的,则无法访问该接口。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/rememberme").rememberMe()
.antMatchers("/admin").fullyAuthenticated()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.rememberMe()
.key("srccde")
.tokenRepository(jdbcTokenRepository())
.and()
.csrf().disable();
}
可以看到:
/rememberme 接口是需要 rememberMe 才能访问
。 /admin
是需要 fullyAuthenticated,fullyAuthenticated
不同于 authenticated,fullyAuthenticated 不包含自动登录的形式,而 authenticated 包含自动登录的形式。 最后剩余的接口(/hello
)都是 authenticated
就能访问。