0%

过滤web请求

过滤web请求

在spring中存在一个DelegatingFilterProxy,是一种特殊的Filter,主要任务就是将工作委托给Filter实现类

使用@EnableWebSecurity注解时引入FilterChainProxy

1
2
3
4
5
6
7
8
9
10
11
12
@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

1
2
3
4
// AbstractSecurityWebApplicationInitializer类实现了WebApplicationInitializer接口,spring会发现,并在web容器中注册DelegatingFilterProxy
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

DelegatingFilterProxy会拦截发往应用中的请求,并将请求委托给springSecurityFilterChain,springSecurityFilterChain本身是另一种特殊的Filter,可以连接任意一个或多个其他的Filter

1
2
3
4
5
6
7
8
9
10
11
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上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Configuration
@EnableWebSecurity // 引入了WebSecurityConfiguration和AuthenticationConfiguration配置
// 继承WebSecurityConfigurerAdapter来自定义配置,只会覆盖修改的配置,不会覆盖不相关的配置
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// 通过重载,配置userDetail服务,认证相关的配置 用户的配置
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 举例:如使用内存中的用户信息 设置用户角色、权限
auth.inMemoryAuthentication() // 内存中认证
.withUser("tom") // 用户
.password("123456") // 密码
.roles("ADMIN") // 角色
.authorities("UPDATE"); // 权限
}
// 通过重载,配置Filter链
public void configure(WebSecurity web) throws Exception {
}

// 通过重载,配置如何通过拦截器保护请求
protected void configure(HttpSecurity http) throws Exception {

http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
}

用户信息获取

首先来将第一个configure方法,来进行用户信息的获取

1
2
3
4
5
6
7
// 通过重载,配置userDetail服务
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 配置userDetailsService
auth.userDetailsService(userDetailsService);
// 还可以进行密码的加密操作
// .passwordEncoder(new CustomPasswordEncoder())
}

使用自定义的用户服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
}
}

详细样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 通过重载,配置如何通过拦截器保护请求
protected void configure(HttpSecurity http) throws Exception {
// 对不同的请求进行不同程度的认证
http
.formLogin() // 配置登录页
.loginPage("/login.html") // 自定义编写登录页面,如果指定登录页,会影响 <li>/authenticate GET - 登录页面地址
// <li>/authenticate POST - 提交登录表单的地址
// <li>/authenticate?error GET - 登陆失败地址
// <li>/authenticate?logout GET - 退出登录地址
.usernameParameter("username") // 定制登录用户名的参数名
.passwordParameter("password") // 定制登录密码的参数名
.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"); // 配置没有权限访问的自定义页面
}

欢迎关注我的其它发布渠道