过滤web请求
在spring中存在一个DelegatingFilterProxy,是一种特殊的Filter,主要任务就是将工作委托给Filter实现类
使用@EnableWebSecurity注解时引入FilterChainProxy
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain() throws Exception { boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty(); if (!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); } return webSecurity.build(); }
可以使用WebApplicationInitializer的方式来配置DelegatingFilterProxy,其会自动为每个url注册springSecurityFilterChain过滤器(也就是DelegatingFilterProxy),添加一个ContextLoaderListener来载入WebSecurityConfig
// AbstractSecurityWebApplicationInitializer类实现了WebApplicationInitializer接口,spring会发现,并在web容器中注册DelegatingFilterProxy
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
DelegatingFilterProxy会拦截发往应用中的请求,并将请求委托给springSecurityFilterChain,springSecurityFilterChain本身是另一种特殊的Filter,可以连接任意一个或多个其他的Filter
private void insertSpringSecurityFilterChain(ServletContext servletContext) {
// DEFAULT_FILTER_NAME就是springSecurityFilterChain
String filterName = DEFAULT_FILTER_NAME;
DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
filterName);
String contextAttribute = getWebApplicationContextAttribute();
if (contextAttribute != null) {
springSecurityFilterChain.setContextAttribute(contextAttribute);
}
registerFilter(servletContext, true, filterName, springSecurityFilterChain);
}
配置Spring Security
使用@EnableWebSecurity注解来启用web安全功能,需要配置在实现了WebSecurityConfigurer或者继承WebSecurityConfigurerAdapter类的bean上
@Configuration
@EnableWebSecurity // 引入了WebSecurityConfiguration和AuthenticationConfiguration配置
// 继承WebSecurityConfigurerAdapter来自定义配置,只会覆盖修改的配置,不会覆盖不相关的配置
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// 通过重载,配置userDetail服务,认证相关的配置
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
}
// 通过重载,配置Filter链
public void configure(WebSecurity web) throws Exception {
}
// 通过重载,配置如何通过拦截器保护请求
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
}
用户信息获取
首先来将第一个configure方法,来进行用户信息的获取
// 通过重载,配置userDetail服务
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
使用自定义的用户服务
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private AdminDao adminDao;
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// 查找用户
Admin user = adminDao.findByName(username);
if (user == null) {
throw new UsernameNotFoundException("Username not found");
}
// 创建权限
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new org.springframework.security.core.userdetails.User(user.getUser_name(), user.getPassword(),authorities);
}
}
详细样例
// 通过重载,配置如何通过拦截器保护请求
protected void configure(HttpSecurity http) throws Exception {
// 对不同的请求进行不同程度的认证
http
.formLogin() // 配置登录页
.loginPage("/login.html") // 自定义编写登录页面
.loginProcessingUrl("/user/login") // 登录访问路径
.defaultSuccessUrl("/index") // 登陆成功之后跳转路径
.and()
.logout().logoutUrl("/logout") // 退出登录的路径
.logoutSuccessUrl("/index") // 退出登录成功的页面
.and()
.authorizeRequests() // // 配置请求级别的认证
.antMatchers("/","/test/").permitAll() // permitAll表示可以直接访问,不需要认证
.antMatchers("/user").authenticated() //authenticated表示必须已经登录了系统
.antMatchers("/admin/").hasAuthority("admin") // hasAuthority用户具备该权限可以访问
.antMatchers("/teacher/").hasAnyAuthority("admin","teacher") // hasAnyAuthority用户具备其中一个权限就可以访问
.antMatchers("/super/").hasRole("admin") //hasRole用户具备该角色可以访问,会拼接一个ROLE_前缀,使用的是角色是 ROLE_admin
.antMatchers("/student/").hasAnyRole("admin","teacher","student") // hasAnyRole如果用户具备其中一个角色就可以访问
.antMatchers("/school/").access("hasRole('admin')") //access使用给定的spel表达式来计算结果
.antMatchers("/ss/").anonymous() // anonymous允许匿名用户访问
.antMatchers("/supper/").denyAll() // denyAll拒绝所有访问
.antMatchers("/full/").fullyAuthenticated() //fullyAuthenticated 用户需要是完整认证(不是通过remeber-me功能认证的)允许访问
.antMatchers("/ip/").hasIpAddress("127.0.0.1") // hasIpAddress 请求来自指定ip可以访问
.antMatchers("/reme/").rememberMe() // 用户通过remember-me功能认证的允许访问
.anyRequest().authenticated() // 其他需要认证
.and()
.requiresChannel().anyRequest().requiresSecure() //requiresSecure配置需要https来进行访问 requiresInsecure配置需要http来进行访问
.and()
.rememberMe().tokenValiditySeconds(3600).key("zhang") // rememberMe功能,保存时间3600s,rememberMe是将token存储在cookie中的,token包括用户名、密码、过期时间和私钥(key)
.and()
.csrf().disable() // 关闭csrf跨站请求伪造防护
.exceptionHandling().accessDeniedPage("/unauth.html"); // 配置没有权限访问的自定义页面
}