- 场景
- 组建工作
- 安检`[漏洞防护(Protection Against Exploits)]`
- 身份验证`[认证(Authentication)]`
- 权益保障`[授权(Authorization)]`
- 处理登机纠纷`[处理安全异常(Handling Security Exceptions)]`
- 航班录入
- 开始运营
- 购票
- 办理手续
- 权限问题
- 登机
某市新建了一座大型机场[Web Application],所有硬件设施已经准备就绪,剩下就是各个部门的人员组建工作。高层刚刚招聘了一位专家[Spring Secirity Framework]开始动手组建安保部门。
组建工作专家一上任就紧锣密鼓的开展工作了。
首先明确了部门的主要职责。一是要保障机场的安全,识别进入机场的非法人员,防止他们进行危害机场行为。二是要保证机场的正常有序地运营,防止旅客占用别人的航班座位等行为。
然后确定了部门的主要工作内容。
- 对入场人员进行安检[漏洞防护(Protection Against Exploits)]。
- 为核实旅客身份[认证(Authentication)]。
- 保障旅客的登机权益[授权(Authorization)]。
- 对于无登机权益的旅客处理安置[处理安全异常(Handling Security Exceptions)]。
需要设立检查点[Security Filter]。检查点会对入场人员进行各种安全检查,例如对所带行李内违禁品的检查、对随身携带物品的检查等等。
需要设立各条登机通道[SecurityFilterChain]。登机通道由一系列的检查点组成。不同航班的旅客通过公共登机通道或者各自独立的登机通道进入飞机。例如国外航班与国内航班的登机通道各不相同、国内航班会有公共的安检点,但是要从不同的登机口登机。
还需要设立一个导航台[FilterChainProxy]。每天都会有很多的航班在机场等待旅客登机,导航台就是让旅客[Client Request]能快速通过各自的航班[URL]找到自己的登机通道。
另外机场大厅的大门[DelegatingFilterProxy]是连接整个机场[Servlet container]和机场大厅[Spring’s ApplicationContext]的桥梁,它是所有旅客进入机场大厅的入口。
下面是Spring Secirity 对应的结构图(其中 Bean Filter0 对应的就是FilterChainProxy):
登机牌办理处[AbstractAuthenticationProcessingFilter]是在上述提到的登机通道[SecurityFilterChain]中的一个站点[Security Filter]。
登机牌办理处设有一个主任[AuthenticationManager]的职位,具体由张三[ProviderManager]负责。因为办理处要针对不同的类型的旅客(普通旅客、特殊旅客、VIP旅客等)有不同的办理流程。所以要为每一类旅客设立一个专员[AuthenticationProvider]来处理。例如,VIP旅客专门由李四来接待处理[e.g. OAuth2LoginAuthenticationProvider]。
每个旅客需要拿着自己的身份证、机票等[credentials],在登机牌办理处办理一个登机牌[Authentication],它是每个旅客身份验证通过的证明。登机牌[Authentication]包含了旅客身份信息[Principal]、机票信息[Credentials]、登机信息(航班号、登机时间、座次号等)[Authorities]。
权益保障[授权(Authorization)]在相应的关口(例如,登机口、 头等舱入口等)[AbstractSecurityInterceptor]都有检票员[AccessDecisionManager]负责检票。旅客需要出示登机牌[Authentication],由检票员检票[AccessDecisionManager::decide]。
检票员[AccessDecisionManager]对于登机牌上的各条信息(航班号、登机时间、座次号等)依次核实[AccessDecisionVoter::vote]。核实结果分为三种情况:通过[ACCESS_GRANTED]、拒绝[ACCESS_DENIED]、弃权不处理[ACCESS_ABSTAIN]。
高层招聘了三个检票员,分别是王五[AffirmativeBased],赵六[ConsensusBased],孙七[UnanimousBased]。
- 王五[AffirmativeBased]会依次查看旅客登机牌上的航班号、登机时间、座次号等信息[Authorities],只要检查到有一个是通过[ACCESS_GRANTED]的,就予以通过。
- 赵六[ConsensusBased]则相对严谨一点,会检查所有的登机信息,只有通过[ACCESS_GRANTED]数量大于拒绝[ACCESS_DENIED]数量的情况下,才予以通过(针对两种结果数量相等的情况,可以通过配置参数决定放行还是禁止)。
- 孙七[UnanimousBased]是最严格的,依次检查相关信息,只要检查到有一个拒绝[ACCESS_DENIED],就会禁止旅客进入。
举例来说,赵六[ConsensusBased]在登机口[e.g. FilterSecurityInterceptor]进行检票:
- 首先要读取旅客所持的登机牌[Authentication]中的航班信息[Authorities::getAuthority]
- 其次要从航班信息库[SecurityMetadataSource]中读取当前所在航班信息[SecurityMetadataSource::getAttributes]
- 接着逐条对比旅客登机信息与机场航班信息[AccessDecisionVoter::vote],比例航班号、登机时间、 座次号。
- 把对比结果累加起来,只要通过[ACCESS_GRANTED]票数大于拒绝[ACCESS_DENIED]票数,就对旅客予以通过。
在身份验证[认证(Authentication)]过程中,往往会出现机票过期、机票无效等一些情况,导致验证不通过[AuthenticationException],无法办理登机牌[Authentication]。
在检票[授权(Authorization)]过程中,也会出现登机牌[Authentication]的登机信息与所在航班或者座次不匹配的情况[AccessDeniedException]。
为此,机场内专程设立了一个处理室[ExceptionTranslationFilter]。
对于身份验证不通过的情况,设了一个接待员[AuthenticationEntryPoint]的岗位。针对不同情况,由不同专员处理。比如,机票丢失需要进行补票[e.g. LoginUrlAuthenticationEntryPoint]。
对于登机信息不匹配的情况,设了一个处理员[AccessDeniedHandler]的岗位。同样针对不同情况,由不同专员处理。比如,在错误的登机口排队登机,则有专员带领到正确的登机口[e.g. InvalidSessionAccessDeniedHandler]。
航班录入在完成的站点设立,人员岗位安排之后,离机场正式运营就剩下最后一步了。就是把航班座次信息[ConfigAttribute]录入到航班信息库[SecurityMetadataSource]中,并设置不同的级别(头等舱、 商务舱、 经济舱)。这样只有买了对应级别舱位机票的旅客才能乘坐相应机舱的相应座位[e.g. hasRole(String role)]。
开始运营好了,机场所有准备工作已经完成,现在开始正常对外运营了。
购票这天,VIP客户李明准备去杭州出差,于是他在网站通过VIP通道购买了一张飞往杭州的机票[Credentials],机场系统记录了他的购票信息(即用户角色绑定)。
办理手续然后他驾车来到了机场,他在通过机场外的一系列关口(机场外围入口、机场停车场入口等[Servlet Container Filter])后,穿过机场大厅的大门[DelegatingFilterProxy],来到了导航台[FilterChainProxy],找到了他要飞往杭州[URL]的航班信息。
接着他按照导航信息,找到登机通道28[SecurityFilterChain]入口,经过一系列安检[SecurityFilter]之后,来到登机牌办理处[AbstractAuthenticationProcessingFilter](该流程步骤与实际情况有所出入,实际场景是先办理登机牌再安检)。李明因为是VIP的缘故,所以径直来到VIP柜台[e.g. OAuth2LoginAuthenticationFilter]办理手续。
登机牌办理处主任[AuthenticationManager]接待了李明,并安排VIP柜台专员李四[e.g. OAuth2LoginAuthenticationProvider]给他办理了登机手续,并交给他一个登机牌并带有VIP字样[e.g. OAuth2LoginAuthenticationToken]。
权限问题接着李明拿着登机牌来到18号登机口[FilterSecurityInterceptor]准备登机。但是检票员[AccessDecisionManager]发现他来错了登机口,他应该是要去28号登机口。于是,机场方面马上派了一个处理员[AccessDeniedHandler]来负责处理这件事。
登机处理员带领李明找到了28号登机口。这次在检票无误后,李明登上了飞往杭州的航班。



