大家知道在spring中有一个基于acegi开发的spring-security的权限管理模块,它是一个轻量级框架。 SpringSecurity能以声明的方式来保护Web应用程序的URL访问,只需简单的配置即可实现。SpringSecurity通过一系列Servlet过滤器为Web应用程序提供了多种安全服务。
配置spring-security
在web.xml中添加过滤器:
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
然后在<classpath>路径下创建配置文件PROJECT-security.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd"> <http auto-config="true" access-denied-page="/access_denied.jsp"> <intercept-url pattern="/admin/**" access="ROLE_ADMIN" /> <intercept-url pattern="/user/**" access="ROLE_USER" /> <form-login login-page="/login.htm" authentication-failure-url="/login.htm?error=1" default-target-url="/" /> <remember-me data-source-ref="dataSource" /> <logout invalidate-session="true" logout-success-url="/" /> <!-- Uncomment to enable X509 client authentication support <x509 /> --> </http> <authentication-provider> <!-- <password-encoder hash="md5" /> --> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select account as username, password, status as enabled from user where account=?" authorities-by-username-query="select account as username, authority from user where account=?" /> </authentication-provider> </beans:beans>
同时将该配置文件加到web.xml的 <context-param> 里。
spring-security中使用角色来分类管理用户权限,如上面的配置中就包含了ROLE_ADMIN和ROLE_USER两个角色,并分别有/admin/和/user/的URL路径下的权限。
在数据库中保存用户
用户的帐号密码有几种不同的方式保存,包括xml中、LDAP和数据库中等。上面使用的是保存到数据库中的方式,使用了之前在applicationContext.xml中配置的dataSource bean。使用数据库保存帐号时,需要按照spring-security规定的字段来建表,有两个相关的表,分别用于保存帐号密码和登录状态。使用MySQL可以这样创建:
CREATE TABLE `user` ( `account` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, `authority` varchar(50) NOT NULL, `status` tinyint(1) NOT NULL, UNIQUE KEY `account` (`account`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `persistent_logins` ( `username` varchar(64) NOT NULL, `series` varchar(64) NOT NULL, `token` varchar(64) NOT NULL, `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`series`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
加密密码
默认spring-security中采用明文方式存储密码,可以通过设置 <password-encoder> 来对密码加密。这时对应的用户注册模块也要将密码以加密后的数据保存到数据库中才行。
import org.springframework.security.providers.encoding.Md5PasswordEncoder; import org.springframework.security.providers.encoding.PasswordEncoder; PasswordEncoder encoder = new Md5PasswordEncoder(); String password = encoder.encodePassword(form.getPassword(), null);
阻止用户重复登陆
可以通过会话控制来防止用户重复登录,这可以通过配置来实现。首先在web.xml中添加监听:
<listener> <listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class> </listener>
然后在PROJECT-security.xml配置文件中的 <http></http> 内添加:
<concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true" />
max-sessions="1" 表示该用户同时登录的最大会话数为1, exception-if-maximum-exceeded="true" 表示阻止超出的用户登录。
在jsp中加入spring-security
spring-security给出了在jsp中使用的接口。用户登录可以使用下面的表单:
<form name='f' action='/PROJECT/j_spring_security_check' method='POST'> <table> <tr><td>用户名:</td><td><input type='text' name='j_username' value=''></td></tr> <tr><td>密码:</td><td><input type='password' name='j_password'/></td></tr> <tr><td></td><td><input type='checkbox' name='_spring_security_remember_me'/> 自动登录</td></tr> <tr><td colspan='2' align="right"><input name="reset" id="reset" type="reset" value="重置" /> <input name="submit" id="submit" type="submit" value="登录" /></td></tr> </table> </form>
根据登录用户进行条件判断可以使用下面的方式:
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <sec:authorize ifAllGranted="ROLE_ANONYMOUS"> <!-- ... --> </sec:authorize> <sec:authorize ifAllGranted="ROLE_USER"> <!-- ... --> </sec:authorize>
在特定jsp页面获取登录用户的帐号的方法是:
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <input name="customer" type="hidden" value="<sec:authentication property='principal.username' />" />
另外, Spring Security 还提供了如下一些功能:
1. remember me ,记住我;
2. form-login 登录控制;
3. 多种身份认证功能;
4. 用户密码加密和“ salt ”功能;
5. http 协议控制;
6. 访问端口控制;
7. Pre-Invocation & After-Invocation 。
spring-security还有很多相关的用法,可以查看 官方的文档 。 http://www.yeolar.com/note/2011/10/19/spring-security/