对于研发和测试人员来说、平时经常需要登录公司或者部门内部的各个平台进行相关的工作,比如:持续集成、工单系统、RMD(项目管理系统)等等。如果挨个平台输入用户名与密码进行登录,是非常繁琐的同时又有很大的安全隐患。为了解决这个问题,我们可以搭建统一的认证授权平台。这样只要用户登录了授权平台就可以免登陆进入授权平台接入的各个子系统。
所以单点登录解决了多系统中间切换的以下问题:
A、免登陆跳转、解决了流程繁琐的问题。
B、无需在各个平台中暴露用户名、密码,解决了安全的问题。
C、用户没法控制各个平台获取的用户信息的范围与时限的问题。
配置客户端详情信息(Client Details):
ClientDetailsServiceConfigurer (AuthorizationServerConfigurer 的一个回调配置项,见上的概述) 能够使用内存或者JDBC来实现客户端详情服务(ClientDetailsService),有几个重要的属性如下列表:
-
clientId:(必须的)用来标识客户的Id。
-
secret:(需要值得信任的客户端)客户端安全码,如果有的话。
-
scope:用来限制客户端的访问范围,如果为空(默认)的话,那么客户端拥有全部的访问范围。
-
authorizedGrantTypes:此客户端可以使用的授权类型,默认为空。
-
authorities:此客户端可以使用的权限(基于Spring Security authorities)。
除了路径选择,我们还通过authenticated()和permitAll()来定义该如何保护路径。authenticated()要求在执行该请求时,必须已经登录了应用。如果用户没有认证,Spring Security的Filter将会捕获该请求,并将用户重定向到应用的登录界面。同时permitAll()方法允许请求没有任何的安全限制。除了authenticated()和permitAll()以外,authorizeRequests()方法返回的对象还有更多的方法用于细粒度地保护请求。如下所示
使用Spring表达式进行安全保护
上面的方法虽然满足了大多数应用场景,但并不是全部。如果我们希望限制某个角色只能在星期二进行访问的话,那么就比较困难了。同时,上面的大多数方法都是一维的,如hasRole()方法和hasIpAddress()方法没办法同时限制一个请求路径。
借助access()方法,我们可以将SpEL作为声明访问限制的一种方式。例如,如下就是使用SpEL表达式来声明具有“ROLE_SPITTER”角色才能访问“/spitter/me”URL:
.antMatchers("/spitters/me").access("hasRole('ROLE_SPITTER')");
让SpEL更强大的原因在于,hasRole()仅是Spring支持的安全相关表达式中的一种。下表列出了Spring Security支持的所有SpEL表达式
现在,如果我们想限制“/spitter/me”URL的访问,不仅需要ROLE_SPITTER角色,还需要来自指定的IP地址,那么我们可以按照如下的方式调用access()方法:
.antMatchers("/spitter/me") .access("hasRole('SPITTER') and hasIpAddress('127.0.0.1')");
@Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.antMatchers("/spitter/me").hasRole("SPITTER")
.antMatchers(HttpMethod.POST,"/spittles").hasRole("SPITTER")
.anyRequest().permitAll();
.and()
.requiresChannel()
.antMatchers("spitter/form").requiresSecure(); //需要加密Https
}
不论何时,只要是对“/spitter/form”的请求,Spring Security都视为需要安全通道(通过调用requiresChannel()确定的)并自动将请求重定向到HTTPS上。
与之相反,有些页面并不需要通过HTTPS传送。例如,首页不包含任何敏感信息,因此并不需要通过HTTPS传送。我们可以使用requiresInsecure()代替requiresSecure()方法,将首页声明为始终通过HTTP传送
.antMatchers("/").requiresInsecure();
防止跨站请求伪造
什么是跨站请求伪造?下面是一个简单的例子:
<form method="POST" action="http://www.spittr.com/Spittles">
<input type="hidden" name="massage" value="I'm a stupid" />
<input type="submit" value="Click here to win a new car!"/>
</form>
这是跨站请求伪造(cross-site request forgery,CRSF)的一个简单样例。简单来讲,入过一个站点欺骗用户提交请求到其他服务器的话,就会发生CSRF攻击,这可能会带来很严重的后果。
从Spring Security3.2开始,默认就会启用CSRF攻击。
Spring Security通过一个同步token的方式来实现CSRF防护。它会拦截状态变化的请求并检查CSRF token。如果请求不包含CSRF token,或token不能与服务器端的token相匹配,请求将会失败,并抛出CsrfException。
Spring Security已经简化了将token放到请求的属性中这一任务。
使用Thymeleaf,只要标签的action属性添加了Thymeleaf命名空间前缀,那么就会自动生成一个“_csrf”隐藏域:
<form method="POST" th:action="@{/spittles}"> ... </form>
使用JSP作为页面模板的话,要做的事非常类似:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
如果使用Spring表单绑定标签的话,标签会自动为我们添加隐藏的CSRF token标签。