〇、上篇回顾
- 上一章介绍了整个框架的建造者,其中
HttpSecurity
也是建造者之一,主要构建目标是FilterChainProxy
对象中一组SecurityFilterChain
的一个 。在实际项目中也是必须用到的类,且功能极多,所以单独拆分一章讲讲其内部各个方法的功能及用法。注:各方法功能说明及示例均来自HttpSecurity源码,如解释不清的时候请参考源码。
一、方法列表索引
- formLogin()
- openidLogin()
- headers()
- cors()
- sessionManagement()
- portMapper()
- jee()
- x509()
- rememberMe()
- authorizeRequests()
- requestCache()
- exceptionHandling()
- securityContext()
- servletApi()
- csrf()
- logout()
- anonymous()
- requiresChannel()
- httpBasic()
- requestMatchers()
- addFilterAt()
- requestMatcher()
- antMatcher()
- mvcMatcher()
- regexMatcher()
- getOrApply()
- setSharedObject()
- beforeConfigure()
- performBuild()
- authenticationProvider()
- userDetailsService()
- getAuthenticationRegistry()
- addFilterAfter()
- addFilterBefore()
- addFilter()
formLogin()
- 说明 :指定支持
基于表单
的身份验证。如果没有指定{@link FormLoginConfigurer#loginPage()}
,将生成一个默认的登录页面。 - 示例1 :最基本的配置是默认生成登录地址是
/login
的登录页,如果验证失败的话会重定向到/login?error
页面。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and().formLogin();
}
- 示例2 :下面这个例子可以配置一些默认值。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and().formLogin()
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/authentication/login")
.failureUrl("/authentication/login?failed")
.loginProcessingUrl("/authentication/login/process");
}
openidLogin()
- 说明 :配置基于
OpenID
的认证 - 示例 :启用
OpenID
认证
@Configuration
@EnableWebSecurity
public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("USER").and()
.openidLogin()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
// 用户名必须与登录用户的OpenID匹配
.withUser(
"https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU")
.password("password").roles("USER");
}
}
headers()
- 说明 :向响应添加
请求安全头
。当使用{@link WebSecurityConfigurerAdapter}
的默认构造函数时,它会被默认激活。 - 示例1 :只调用
{@link HttpSecurity#headers()}
,其实相当于调用了以下的所有方法
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.contentTypeOptions()
.and()
.xssProtection()
.and()
.cacheControl()
.and()
.httpStrictTransportSecurity()
.and()
.frameOptions()
.and()
// ...
;
}
- 示例2:当然你也可以禁用 headers()
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.disable()
;
}
- 示例3:你也可以使用部分请求头,前提你需要调用
{@link HeadersConfigurer#defaultsDisabled()}
先关闭所有,然后打开你想要的请求头
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.defaultsDisabled()
.cacheControl()
.and()
.frameOptions()
.and()
// ...
;
}
- 示例4:同样你可以选择默认值,而关闭某些特定的请求头
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.frameOptions()
.disable()
.and()
// ...
;
}
cors()
- 说明:添加要使用的
{@link CorsFilter}
。如果提供了一个名为corsFilter
的bean,则使用{@link corsFilter}
添加该Filter。
sessionManagement()
-
说明:允许配置
Session
会话管理 -
示例:
- 下面的配置演示如何强制一次只对用户的单个实例进行身份验证。如果用户使用用户名
user
进行身份验证而没有注销,并且尝试再次使用user
进行身份验证,第一个会话将被强制终止并发送到/login?expired
URL。 - 当使用
{@link SessionManagementConfigurer#maximumSessions()}
时,不要忘记为应用程序配置{@link HttpSessionEventPublisher}
,以确保过期的会话被清除。
- 下面的配置演示如何强制一次只对用户的单个实例进行身份验证。如果用户使用用户名
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin().permitAll()
.and()
.sessionManagement().maximumSessions(1)
.expiredUrl("/login?expired");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password")
.roles("USER");
}
portMapper()
- 说明:允许配置
{@link HttpSecurity#getSharedObject()}
中可用的{@link PortMapper}
端口映射。 - 示例:提供的
{@link SecurityConfigurer}
对象在从HTTP重定向到HTTPS,或从HTTPS重定向到HTTP时,使用这个配置作为默认的{@link PortMapper}
。默认情况下,Spring Security使用{@link PortMapperImpl}
将HTTP端口8080映射到HTTPS端口8443,将HTTP端口80映射到HTTPS端口443。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.formLogin().permitAll()
.and()
.portMapper().http(9090).mapsTo(9443).http(80).mapsTo(443);
}
jee()
- 说明:配置
基于容器
的预认证。在本例中,身份验证由Servlet容器管理。 - 示例:这个示例将使用
{@link HttpServletRequest}
上找到的用户,如果用户是角色ROLE_USER
或ROLE_ADMIN
,则将其添加到生成的{@link Authentication}
中。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.jee().mappableRoles("ROLE_USER", "ROLE_ADMIN");
}
x509()
- 说明:配置基于
X509
的预认证。 - 示例:这个示例将尝试从
X509
证书中提取用户名。请记住,需要配置Servlet容器来请求客户端证书,这样才能工作。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.x509();
}
rememberMe()
- 说明:配置
Remember Me
认证。 - 示例:下面的配置演示了如何允许基于令牌的 remember me 身份验证。在进行身份验证时,如果名为
remember-me
的HTTP参数存在,那么即使在他们的{@link javax.servlet.http.HttpSession}
过期失效之后,用户也会被记住。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and().formLogin()
.permitAll().and()
.rememberMe();
}
authorizeRequests()
- 说明:配置基于
{@link HttpServletRequest}
使用限制访问 - 示例1:最基本的例子是配置所有 url 都需要有
ROLE_USER
角色。下面这个配置示例要求对每个URL进行身份验证,并将授予用户admin
和user
不同的访问权限。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("ADMIN", "USER");
}
- 示例2:也可以配置多个url。下面的配置要求对每个URL进行身份验证,并且只允许
admin
用户访问以/admin/
开头的URL。任何一个用户都可以访问所有其他url。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/**").hasRole("USER")
.and()
.formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("ADMIN", "USER");
}
- 示例3:注意匹配器是按顺序匹配的。因此以下是无效的,因为第一个匹配器匹配每个请求,并且永远不会到达第二个匹配器。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin();
}
requestCache()
- 说明:允许配置
请求缓存
。例如,一个受保护的页面/protected
可能会在身份验证之前被请求。应用程序将用户重定向到登录页面,身份验证之后,Spring Security将用户重定向到最初请求的受保护页面/protected
。当使用{@link WebSecurityConfigurerAdapter}
时,会被默认激活。
exceptionHandling()
- 说明:允许配置
异常处理
。当使用{@link WebSecurityConfigurerAdapter}
时,会被默认激活。
securityContext()
- 说明:在
{@link HttpServletRequest}
之间的{@link SecurityContext}
上建立{@link SecurityContextHolder}
的管理。当使用{@link WebSecurityConfigurerAdapter}
时,会被默认激活。
servletApi()
- 说明:将
{@link HttpServletRequest}
方法与{@link SecurityContext}
上的值集成起来。当使用{@link WebSecurityConfigurerAdapter}
时,会被默认激活。
csrf()
- 说明:添加
CSRF
支持 - 示例:当使用
{@link WebSecurityConfigurerAdapter}
时,会被默认激活。你可以禁用它
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
logout()
- 说明:提供
注销
的支持。当使用{@link WebSecurityConfigurerAdapter}
时,会被默认激活。默认情况下,访问URL/logout
将使HTTP会话失效,清除配置的所有{@link HttpSecurity#rememberMe()}
身份验证,清除{@link SecurityContextHolder}
,然后重定向到/login?success
,从而使用户退出。 - 示例:下面的配置,当
/custom-logout
接口被调用时,会走注销流程。注销将删除名为remove
的cookie,清除SecurityContexHolder
,但是不会使HttpSession
失效,在完成上面动作之后重定向到/logout-success
。
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("USER")
.and().formLogin()
.and()
.logout().deleteCookies("remove").invalidateHttpSession(false)
.logoutUrl("/custom-logout")
.logoutSuccessUrl("/logout-success");
}
anonymous()
- 说明:允许配置
匿名用户
的表示方式。当使用{@link WebSecurityConfigurerAdapter}
时,会被默认激活。默认情况下,匿名用户将用{@link org.springframework.security.authentication.AnonymousAuthenticationToken}
,包含角色ROLE_ANONYMOUS
。 - 示例1:下面的配置演示了如何指定匿名用户应该包含角色
ROLE_ANON
。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and().formLogin()
.and()
.anonymous().authorities("ROLE_ANON");
}
- 示例2:下面演示了如何将匿名用户表示为空。注意,假设启用了匿名身份验证可能会导致代码中出现空指针异常。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and().formLogin()
.and()
.anonymous().disable();
}
requiresChannel()
- 说明:配置
通道安全
(HTTPS访问)。为了使该配置有用,至少必须提供一个到所需通道的映射。 - 示例:下面的例子演示了如何为每个请求要求HTTPS。不建议只支持某些请求需要HTTPS,因为允许HTTP的应用程序会引入许多安全漏洞。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and().formLogin()
.and().requiresChannel().anyRequest().requiresSecure();
}
httpBasic()
- 说明:配置
HTTP基本认证
。 - 示例:下面的示例演示如何为应用程序配置HTTP基本身份验证。默认的领域是
Spring Security Application
,但是可以使用{@link HttpBasicConfigurer#realmName()}
自定义。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
}
requestMatchers()
-
说明:
- // TODO … 。如果只需要一个
{@link RequestMatcher}
,可以考虑使用{@link #mvcMatcher()}
、{@link #antMatcher()}
、{@link #regexMatcher()}
、或{@link #requestMatcher()}
。 - 调用
{@link #requestMatchers()}
不会覆盖之前对{@link #mvcMatcher()}
、{@link #requestMatchers()}
、{@link #antMatcher()}
、{@link #regexMatcher()}
和{@link #requestMatcher()}
的调用。
- // TODO … 。如果只需要一个
-
示例1:下面配置了以
/api/
和/oauth/
开头的URL,无需认证。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**", "/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
}
- 示例2:下面的配置与前面的配置相同
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.antMatchers("/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
}
- 示例3:下面的配置也与上面的配置相同
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.requestMatchers()
.antMatchers("/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
}
addFilterAt()
- 说明:在指定的过滤器位置添加过滤器。
requestMatcher()
- 说明:允许将
{@link HttpSecurity}
配置为只在匹配所提供的{@link RequestMatcher}
时被调用。如果需要更高级的配置,可以考虑使用{@link #requestMatchers()}
。
antMatcher()
- 说明:允许将
{@link HttpSecurity}
配置为只在匹配所提供的ant
模式时被调用。如果需要更高级的配置,可以考虑使用{@link #requestMatchers()}
或{@link #requestMatcher()}
。
mvcMatcher()
- 说明:允许将
{@link HttpSecurity}
配置为只在匹配所提供的Spring MVC
模式时被调用。如果需要更高级的配置,可以考虑使用{@link #requestMatchers()}
或{@link #requestMatcher(requestMatcher)}
。
regexMatcher()
- 说明:允许将
{@link HttpSecurity}
配置为只在匹配所提供的正则表达式
模式时被调用。如果需要更高级的配置,可以考虑使用{@link #requestMatchers()}
或{@link #requestMatcher()}
。
getOrApply()
- 说明:如果
{@link SecurityConfigurer}
已经被指定获取原始的,否则应用新的{@link SecurityConfigurerAdapter}
配置。
performBuild()
- 说明:实现的父类
AbstractConfiguredSecurityBuilder
的抽象接口,目的是创建SecurityFilterChain实例
二、系列文章
Spring Security 系列
- 《手把手教你如何使用Spring Security(上):登录授权》
- 《手把手教你如何使用Spring Security(中):接口认证》
- 《手把手教你如何使用Spring Security(下):访问控制》
- 《Spring Security源码(一):整体框架设计》
- 《Spring Security源码(二):建造者详解》
- 《Spring Security源码(三):HttpSecurity详解》
- 《Spring Security源码(四):配置器详解》
- 《Spring Security源码(五):FilterChainProxy是如何创建的?》
- 《Spring Security源码(六):FilterChainProxy是如何运行的?》
- 《Spring Security源码(七):设计模式在框架中的应用》
- 《Spring Security源码(八):登录认证源码流程》
- 《Spring Security源码(九):过滤器链上的过滤器是如何排序的?》
- 《Spring Security源码(十):权限访问控制是如何做到的?》
Spring Security OAuth 系列
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。