9.1 Spring Security简介
Spring Security 是为基于Spring的应用程序提供声明式安全保护的安全性框架。SpringSecurity充分利用了DI和AOP技术。本章将使用SpringSecurity保证Web安全性。
9.1.1 SpringSecurity模块
SpringSecurity被分成了11个模块
ACL | AccessControlList访问控制列表为域对象提供安全性 |
---|---|
切面 | 当使用SpringSecurity注解时,会使用基于AspectJ的且米娜,而不是使用标准的SpringAOP |
CAS客户端 | 提供与Jasig的中心认证服务(Central Authentication Service)进行集成的功能 |
配置 | 包含通过XML和Java配置SpringSecurity的功能支持 |
核心 | 提供SpringSecurity基本库 |
加密 | 提供了加密和密码编码的功能 |
LDAP | 支持基于LDAP进行认证 |
OpenID | 支持使用OpenID进行集中式认证 |
Remoting | 提供了对SpringRemoting的支持 |
标签库 | SpringSecurity的JSP标签库 |
Web | 提供了SpringSecurity基于Filter的Web安全性支持 |
其中Core和Configuration模块必须包含在应用程序的类路径下。一般为了保护web应用我们还需要Web模块。
9.1.2 过滤Web请求
SpringSecurity借助一系列ServletFilter来提供各种安全性功能。
DelegatingFilterProxy是一个特殊的ServletFilter。它将工作委托给javax.servlet.Filter实现类,这个实现类作为一个
在web.xml中配置过滤器(方法1)
|
|
在Java中配置(方法2)
|
|
不管我们使用web.xml配置还是AbstractSecurityWebApplicationInitializer得子类来配置DelegatingFilterProxy,它都会拦截发往应用中的请求,并将请求委托给ID为springSecurityFilterChain的bean。
配置Security安全细节
|
|
这个简单的默认配置指定了该如何保护HTTP请求,以及客户端认证用户的方案。通过调用authorizeRequest()和anyRequest().authenticated()就会要求所有进入应用的HTTP请求都要进行认证。他也配置SpringSecurity支持基于表单的登陆以及HTTPBasic方式的认证。
由于没有配置configure(AuthenticationManagerBuilder)方法,所以没有用户存储支撑认证过程。没有人能够登陆成功。
TODO:
- 配置用户存储
- 指定哪些请求需要认证,哪些请求不需要认证,以及所需要的权限
- 提供一个自定义的登陆界面,替代原来简单的默认登录页。
- 基于安全限制,有选择的在Web视图上显示特定的内容。
9.2 选择查询用户详细信息的服务
SpringSecurity能够基于各种数据存储来认证用户。它内置了多种常见的用户存储场景,如内存、关系型数据库以及LDAP。
9.2.1 使用基于内存的用户存储
|
|
9.2.2 基于数据库表进行认证
SpringSecurity会内置一些查询语句,当查找用户信息时会自动执行。
当然我们也可以自定义查询语句来获取用户信息。如下是相关java配置。
将默认的sql查询替换为自定义的设计时,要遵循查询的基本协议。
- 所有查询都将用户名作为唯一的参数
- 认证查询会选取用户名、密码以及启用状态信息。
- 权限查询会选取0行或多行包含该用户名以及其权限信息的数据。
- 群组权限查询会选取0行或多行数据,每行数据中都会包括群组ID、群组名称以及权限。
|
|
其中datasource是通过自动装配注入的,因此我们需要在root中或者xml中先配置一下数据源。
|
|
之后再访问web层就可以使用数据库中已经存储的用户去登陆SpringSecurity校验界面了。
补充:一般情况下数据库中的密码并不是明文存储的,因此我们需要一个密码转换方法将SpringSecurity从DB中获取到的密码进行解码。
举个栗子:DB中username=niko,password=niko_salt(这是密文哦,用户注册后系统加工后的处理结果)。
那么通过MyPasswordDecoder类处理后,我们通过SpringSecurity登录验证的输入为:niko,niko就能正常访问了。
|
|
9.2.3 自定义查询用户服务
|
|
9.3 拦截请求
针对不同的功能进行不同等级的安全认证是项目中经常会用到的。
|
|
以上配置指定了部分url禁止访问,匹配url的字符串支持Ant风格(antMatchers)的通配符。也可以在一个matcher中指定多个url链接,用逗号隔开。url也支持正则表达式regexMachers和anyRequest。.regexMachers("spitters/.*").authenticated()
和/spitters/**
所拦截的url是一样的。
用来定义如何保护路径的配制方法
access(String) | 如果给定的SpEL表达式计算结果为true,就允许访问。 |
---|---|
anonymous() | 允许匿名用户访问 |
authenticated() | 允许认证过的用户访问 |
denyAll() | 无条件拒绝所有访问 |
fullyAuthenticated() | 如果用户是完整认证的话(不是通过Remember-me功能认证的)就允许访问 |
hasAnyAuthority(String…) | 如果用户具备给定全险种的某一个的话,就允许访问 |
hasAnyRole(String…) | 如果用户具备给定角色中的某一个的话,就允许访问 |
hasAuthority(String) | 如果用户具备给定权限的话,就允许访问 |
hasIpAddress(String) | 如果请求来自给定IP地址的话,就允许访问。 |
hasRole(String) | 如果用户具备给定角色的话,就允许访问 |
not() | 对其他访问方法的结果求反 |
permitAll() | 无条件允许访问 |
rememberMe() | 如果哟过户是通过Remember-me功能认证的,就允许访问 |
我们可以将任意数量的antMachers、regexMatcgers、anyRequest连接起来,以满足web安应用安全规则的需要。这些规则按照给定的顺序发挥作用,所以必须将最具体(细粒度)的请求路径放在前面,而最不具体的路径(anyRequest)放在最后面。否则后面的路径配置将会被前面的覆盖。
9.3.1 使用Spring表达式进行安全保护
使用SpEL表达式可以使安全限制更加灵活强大,以上表格展示了所有限制方法,但是假如我们需要使用一些特殊的安全机制,那么可以使用SpEL表达式。
| authentication | 用户的认证对象 |
| — | — |
| denyAll | 结果始终为false |
| hasAnyRole(list of roles) | 如果用户被授予了列表中的人已制定角色,结果为true |
| hasRole(role) | 如果用户被授予了指定的角色,结果为true |
| hasIpAddress(IP) | 如果来自指定的IP,结果为true |
| isAnonymous() | 如果当前用户为匿名用户,结果为true |
| isAuthenticated() | 如果当前用户进行了认证,结果为true |
| isFullyuAuthenticated() | 如果当前用户进行了完整认证,结果为true |
| isRememberMe() | 如果当前用户是通过Remember-me自动认证的,结果为true |
| permitAll | 结果为true |
| principal | 用户的principal对象 |
.antMachers(“/spitter/me”).access(“hasRole(‘ROLE_SPITTER’) and hasIpAddress(‘192.168.1.2’)”)
9.3.2 强制通道的安全性
将访问路径强制转换为https
|
|
9.3.3 防止跨站请求伪造
SpringSecurity会默认启动CSRF防护,因此我们无法向其他站点提交请求,以防止页面在被篡改的情况下站点被CSRF攻击。我们可以在jsp页面中的form表单中添加csrf隐藏域(后台传过来的)。
|
|
或者在SpringSeccurity中禁用CSRF防护。
|
|
9.4 认证用户
上面的安全配制方法,虽然配置了一些用户权限问题,但是没有设置登陆界面,所以你咋让我认证啊?
解决方案如下
|
|
9.4.1 添加自定义的登陆页
自己造一个
|
|
注意表单提交位置、输入域名称就可以了,简单的一匹。
|
|
Controller
|
|
9.4.2 启用HTTP Basic认证
对于普通用户来说,展现一个login表单还可以,但是对于应用程序来说就需要另外一种验证方式了。
启用HTTP Basic认证的方式很简单。
|
|
模拟Basic认证请求
9.4.3 RememberMe功能和注销功能
|
|
9.5 小结
Spring Security提供了一种简单、灵活且强大的机制来保护Web应用程序。借助一系列Servlet Filter能够控制对Web资源的访问,包括MVC控制器。借助于Java配置模型,能够简洁的声明Web安全性功能。
当认证用户是,可以使用基于内存用户库、关系型数据库、LDAP目录服务器来配置认证功能。