(一) Spring Security简介
一句话书面用语:Spring Security是为基于Spring的应用程序提供声明式安全保护的安全性框架(目前最新是Spring Security 4.0版本,2015,07,10)。
只要知道Spring Security是基于Spring AOP和Servlet过滤器实现的安全性框架,解决Web应用中的安全问题,安全问题主要包含两个方面:
1. 认证(authentication)
2. 授权(authorization,或者叫访问控制)
认证解决“你是谁“ 的问题,而授权解决”你可以干啥“的问题。
(二)Spring Security应用
网上很多SpringSecurity应用详解,但是第一次使用还是碰到很多问题,这里讲自己遇到的问题记录下来,希望对需要的朋友有些帮助。首先介绍下Demo的一些基本信息:界面用JSP,后台S2SH
1.SpringSecurity用户认证策略(最常使用的是 实现UserDetailsService接口的用户数据库认证)
所谓用户认证策略,说白了就是你输入登录名和密码后,程序如何验证该用户名和密码是否有效。SpringSecurity提供很多用户认证策略,比如:基于内存,JDBC,LDAP等。最常用到的是从数据库中查询该登录用户的用户名和密码是否有效),所以基于JDBC的认证方式是一种选择;但是在我们的Web应用中,肯定有关于用户的增删改查方法的实现。这样的话采用实现UserDetailsService接口的方式进行用户认证会方便很多。下面是具体实现的代码:
@Service("userDetailsService") publicclassUserDetailsServiceImpl implements UserDetailsService { @Resource private UserService userService; @Override public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException { // TODO Auto-generated method stub Users user = userService.getUserByUserName(username); MyUserDetails u = null; intid = user.getId(); String section = user.getSection(); String userName = user.getUserName(); if(user != null){ u= new MyUserDetails(username,user.getPassword(),id,section,userName,findUserAuthorities(user)); } return u; } publicList<GrantedAuthority> findUserAuthorities(Users user){ List<GrantedAuthority> autthorities = new ArrayList<GrantedAuthority>(); List<Permission> roles = userService.getPermissionByUser(user); for (Permission role : roles) { autthorities.add(newSimpleGrantedAuthority(role.getRoleCode())); } return autthorities; } }
对以上代码解析:
(1).UserDetailsService是Spring Security中的接口,其内只定义了一个方法:
UserDetailsloadUserByUsername(String
username);
当用户提交登陆表单后,SpringSecurity框架就会调用loadUserByUsername方法,传入的参数username就是登录表单中的name=”j_username”
的标签值,返回一个UserDetails对象。
UserDetails也是Security框架中的接口,并且框架中也有一个默认的实现类User,但是User只有username,password,authorities属性,可是在Web应用中我们经常会用到用户的其他信息(比如,userId,email,age等),这种情况下我们可以不用SpringSecurity的User类,自定义一个类,但是必须实现UserDetails接口,并且必须包含username,password,authorities三个属性(其他属性根据自己的需要可以任意添加),本例中就是MyUserDetails,属性包含(username,password,section部门)。
(2).
@Resource
private UserService
userService;
这个是自定义的提供用户增删改查的service接口(很多应用应该都会有)
(3). Users user =
userService.getUserByUserName(username);
这里的Users是程序中自定义的用户类,通过userService的getUserByUserName获取Users对象。
下面列出的是使用SpringSecurity过程中遇到的问题:
1.接收不到j_username参数问题
开始的登陆界面中的form表单中用户名和密码的input标签分别是:
<form
name="form"
method="post"action="j_spring_security_check">
<input
name="j_username"id="j_username"
type="text"/>
<input
name="j_password"id="j_password "
type="text"/>
</form>
这是默认的参数名,form中的action属性值"j_spring_security_check" 也是默认的,但是表单提交后,之前提到的loadUserByUsername(String username)方法中无法接受到j_username参数。
解决方法:在<form-login >中添加username-parameter和password-parameter属性,显示的指定接受的参数名称。
如下:
<form-login
login-page=‘/manage/login.jsp‘
username-parameter=‘j_username‘
password-parameter=‘j_password‘
/>
2.<sec:authorize>无效问题(ROLE_开头)
SpringSecurity提供了视图级别的保护,即我们使用不同的身份登录,通常需要显示的界面不同,比如管理员登录时可以进行增删改查操作,但是普通用户可能只能查看,增加,修改,删除的按钮此时就不需要显示了。
如下所示:
<sec:authorize
access="hasRole(‘ROLE_ADMIN‘)">
<a
href="manage/user/userAction-userAdd.do">新增</a>
</sec:authorize>
此时登录用户拥有ROLE_ADMIN身份是才会显示“新增”按钮。但是有时<sec:authorize>标签会无效,这是因为角色必须以RLOE_开头才能被识别。
3无法请求Struts2的Action(CSRF,403 Forbidden)
<a
href="manage/user/userAction-userAdd.do">新增</a>
程序中出现上面这个按钮,点击过后我希望跳转到添加用户的界面,但此时可能出现点击过后,没有跳转到用户新增页面。这时FireDebug控制台出现403Forbidden错误提示。
这是应为SpringSecurity框架提供了预防CSRF(跨站请求伪造)的功能。在提交请求时,该请求被CrsfFilter拦截,验证_crsf的token是否有效。
注意:只有在使用POST方法提交时才会被拦截。
解决方法有两种:
(1)禁用此功能,只要在<http
>标签内配置一下元素即可。
<http 。。。>
。。。。。
<csrf
disabled="true"></csrf><!--
防止跨站请求伪造攻击 -->
</http
>
(2)提供验证需要的token。如下所示:
<a
href="manage/user/userAction-userAdd.do? ${_csrf.parameterName}=${_csrf.token}">新增</a>
4,iframe加载问题(x-frame-options)
当我们的jsp页面中使用了iframe时,可能出现该iframe中的内容无法加载的问题。
这是因为SpringSecurity提供的HeaderWriterFilter为response添加安全header信息。
其中就有一项是:X-Frame-Options选项。
该选项有三个值:
DENY:浏览器拒绝当前页面加载任何frame页面。
SAMEORIGHT:允许加载本站点内的页面。
ALLOW-FROM:允许frame加载任何页面。
SpringSecurity中默认设置X-Frame-Options的值为DENY(可以从FireDebug中查看)
解决方法:
禁止HeaderWriterFilter为response添加安全header信息。如下:
<http 。。。>
。。。。。
<!-- 配置HeaderWriterFilter,为response添加安全header信息-->
<headers
defaults-disabled="true">
<cache-control/>
</headers>
。。。。
</http
>
5.<http>元素及其子元素的常用属性
SpringSecurity是基于过滤器实现自己的安全功能的,所以有必要知道常用的过滤器的配置(xml形式)及功能。这些过滤器基本是在<http>元素内配置的,下面就介绍下常用的配置。
<http>元素
包含的属性:
auto-config=”true” : 自动配置是个默认的过滤器。
use-expressions=“true”:允许使用EL-expressions。
。。。。
下面是<http>元素的子元素:
(1)<form-login>(添加UsernamePasswordAuthenticationFilter过滤器)
属性:
login-page:登录界面的url,如: login-page=‘/manage/login.jsp‘
username-parameter:request中包含username的参数名,默认username,
password-parameter:同上,默认是password。
注意(SpringSecurity4之前默认都是j_username,j_password,这点要注意)
login-processing-url:处理登录请求的url, 这里的值必须和jsp页面中form表单的action的值一致。
authentication-failure-url:认证失败跳转页面url。
default-target-url:验证成功默认跳转的页面url。
always-use-default-target:若为true,始终default-target-url指定页面进入系统。
(2)<access-denied-handler>(用户被拒绝访问作何处理,比如返回一个错误界面)
属性:
error-page : 被拒绝访问后,返回errorpage的url地址。
ref:指向AccessDeniedHandler类型的bean。
(3)<headers>(前面提到过,该元素用来配置response的header信息)
属性:
defaults-disabled :可选,禁止response的默认header信息。默认为false(即header中包含默认的基本信息)
disabled:可选,默认false。
待续。。。。
版权声明:本文为博主原创文章,未经博主允许不得转载。