SpringSecurity学习笔记(一)—— Java配置
Web安全
- 创建Security过滤器(通过springSecurityFilterChain负责所有安全过滤请求)
基本例子
`
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager inMemoryManager = new InMemoryUserDetailsManager();
inMemoryManager.createUser(User.withUsername("admin").password("123456").roles("SuperAdmin").build());
return inMemoryManager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//确保任何请求应用程序需要经过身份验证的用户
.anyRequest().authenticated()
.and()
//允许用户进行身份验证和基于表单的登录
.formLogin()
.and()
//允许用户通过HTTP基本认证验证
.httpBasic();
}
}
`
- 验证应用程序每一个URL
- 生成登录表单对象
- 通过用户/密码进行表单验证
- 用户注销
- 阻止CSRF攻击
- 设置安全请求头
- 集成servletAPI
AbstractSecurityWebApplicationInitializer确保springSecurityFilterChain得到注册
Http安全和表单登录
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//确保任何请求应用程序需要经过身份验证的用户
.anyRequest().authenticated()
.and()
//允许用户进行身份验证和基于表单的登录
.formLogin()
.and()
//允许用户通过HTTP基本认证验证
.httpBasic();
}
<http>
<intercept-url pattern="/**" access="authenticated"/>
<form-login />
<http-basic />
</http>
认证请求
.authorizeRequests()
.antMatchers("/admin","/system","/resource").permitAll()
.antMatchers("/product").hasRole("admin")
.antMatchers("/dba").access("hasRole('admin') and hasRole('dba')")
.anyRequest().authenticated()
注销
- 清除http session
- 清除rememberme状态
- 清除上下文SecurityContextHolder
重定向/login?logout
.logout() //如果开启CSRF,请求必须为POST .logoutUrl("/logout") //注销成功后,跳转页面 .logoutSuccessUrl("/index") //清除无效session .invalidateHttpSession(true) //自定义LogoutSuccessHandler.class。如果该类生效。忽略logoutSuccessUrl .logoutSuccessHandler(logoutSuccessHandler) //添加LogoutHandler .addLogoutHandler(logoutHandler) //删除cookie .deleteCookies(cookieNamesToClear)
LogoutSuccessHandler 的实现类
注销成功后发生的操作
- SimpleUrlLogoutSuccessHandler
- HttpStatusReturningLogoutSuccessHandler
LogoutHandler 的实现类
处理必要的清理。例如cookie等
- PersistentTokenBasedRememberMeServices
- TokenBasedRememberMeServices
- CookieClearingLogoutHandler
- CsrfLogoutHandler
- SecurityContextLogoutHandler
更多关于注销的文档
通过钩子方法实现自动登录。RememberMeServices接口方法类似如下
autoLogin(req,res)
loginSuccess(req,res)
loginFail(req,res)
用于记录当前用户。HttpServletRequest.logout()被调用,需要编写一个响应。
mvc
.perform(logout())
高级认证
In-Memory
@Bean
public UserDetailsService userDetailsService() throws Exception {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
manager.createUser(User.withUsername("admin").password("password").roles("USER","ADMIN").build());
return manager;
}
JDBC
@Autowired
private DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
自定义授权认证
@Bean
public SpringAuthenticationProvider springAuthenticationProvider() {
return new SpringAuthenticationProvider();
}
自定义身份认证
@Bean
public SpringDataUserDetailsService springDataUserDetailsService() {
return new SpringDataUserDetailsService();
}
自定义密码加密
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
多个HttpSecurity
@EnableWebSecurity
public class MultiHttpSecurityConfig {
@Bean
public UserDetailsService userDetailsService() throws Exception {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
manager.createUser(User.withUsername("admin").password("password").roles("USER","ADMIN").build());
return manager;
}
@Configuration
@Order(1) 1
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
方法安全
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
}
public interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account[] findAccounts();
@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
}
后置处理
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
fsi.setPublishAuthorizationSuccess(true);
return fsi;
}
})
自定义DSLs
public class MyCustomDsl extends AbstractHttpConfigurer<CorsConfigurerMyCustomDsl, HttpSecurity> {
private boolean flag;
@Override
public void init(H http) throws Exception {
// any method that adds another configurer
// must be done in the init method
http.csrf().disable();
}
@Override
public void configure(H http) throws Exception {
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
// here we lookup from the ApplicationContext. You can also just create a new instance.
MyFilter myFilter = context.getBean(MyFilter.class);
myFilter.setFlag(flag);
http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
}
public MyCustomDsl flag(boolean value) {
this.flag = value;
return this;
}
public static MyCustomDsl customDsl() {
return new MyCustomDsl();
}
}
META-INF/spring.factories.
org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyCustomDsl