Spring Security 在 Servlet 请求中实现鉴权
1. 前言
Servlet 是 Java Web 应用的最常见场景,Spring Security 对 Servlet 的权限认定过程实现了规范化和流程化。
本节主要讨论在 Servlet 应用中,如何通过 Spring Security 实现鉴权。
2. Servlet 权限控制的流程
Servlet 鉴权主要围绕着 FilterSecurityInterceptor
类展开,该类作为一个安全过滤器,被放置在 FilterChainProxy
中。
FilterSecurityInterceptor
从 SecurityContextHolder
中获取 Authentication
对象;
FilterSecurityInterceptor
从 HttpServletRequest
、HttpServletREsponse
、 FilterChain
中创建 FilterInvocation
对象;
- 将创建的
FilterInvocation
对象传递给 SecurityMetadataSource
用来获取 ConfigAttribute
对象集合;
- 最后,将
Authentication
、FilterInvocation
和 ConfigAttribute
对象传递给 AccessDecisionManager
实例验证权限:
- 如果验证失败,将抛出
AccessDeniedException
异常,并由 ExceptionTranslationFilter
接收并处理;
- 如果验证通过,
FilterSecurityInterceptor
将控制权交还给 FilterChain
,使程序继续执行。
3. Servlet 权限控制的配置实现
默认情况下,Spring Security 的权限要求所有的请求都需要首先通过认证。相当于以下配置描述:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize -> authorize
.anyRequest().authenticated()
);
}
如果我们需要配置 Spring Security 对不同请求有不同的处理规则时,可通过以下方式修改配置:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize -> authorize
.mvcMatchers("/resources/**", "/signup", "/about").permitAll()
.mvcMatchers("/admin/**").hasRole("ADMIN")
.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().denyAll()
);
}
- 指定了多种规则,每种规则按照其配置的顺序决定优先级;
- 匹配了多个 URL 规则,对于
/resources
、/signup
、/about
允许任何用户访问;
- 任何以
/admin/
开头的地址都要求用户具有管理员权限 ROLE_ADMIN
,其中 ROLE_
前缀是 Spring Security 默认添加的,用户无需做特殊处理;
- 任何以
/db/
为开头的地址需要同时拥有 ROLE_ADMIN
和 ROLE_DBA
角色;
- 没有被上述 URL 地址匹配的地址都将被禁止访问,加上这一条非常有助于提升系统的安全性。
4. 小结
本节讨论了如何用 Spring Security 规范化 Servlet 鉴权过程:
- Spring Security 对 Servlet 请求的权限控制,主要依赖于
FilterSecurityInterceptor
实现;
- Spring Security 默认对每一个 Servlet 请求都要求用户已通过认证;
- Spring Security 支持对 Servlet 的不同 URL 规则配置不同的权限规则。
下节我们讨论如何通过「访问控制表达式」实现多样化的鉴权规则。