Spring Security 3.1 自定義實例之登陸
Spring Security的前身是Acegi,功能強大,配置也比較復雜,我也是新手,先通過動手實現一個登陸驗證實例來進入Spring Security的世界吧!
1.准備:
下載Spring Security:官方下載地址:
http://www.springsource.org/spring-security 在下載之前Spring會要你填寫一些基本信息,然后就會自動跳轉到下載地址,
目前最新版本為spring-security-3.1.0.RELEASE,解壓后在dist目錄下可以看到:

其中兩個War包是實例,*-source.jar是源代碼
將dist中的Jar包全部導入到工程中,如圖:

2.修改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>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath*:App*.xml</param-value>
- </context-param>
3.新建AppSecurity.xml,如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans:beans xmlns="http://www.springframework.org/schema/security" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:beans="http://www.springframework.org/schema/beans" 5 xsi:schemaLocation=" 6 http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/security 9 http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 10 11 <http auto-config="true"> 12 <intercept-url pattern="/*" access="ROLE_USER" /> 13 </http> 14 15 <authentication-manager alias="authenticationManager"> 16 <authentication-provider> 17 <user-service> 18 <user name="test" password="test" authorities="ROLE_USER" /> 19 </user-service> 20 </authentication-provider> 21 22 </authentication-manager> 23 </beans:beans>
這個xml文件里用了Spring Security的最簡單配置 <http auto-config="true"/>含義就是使用Spring Security自動為我們設置一些參數,然后聲明了訪問所有URL都需要為ROLE_USER,然后在authentication-manager用硬編碼的形式定義了一個用戶test,權限為ROLE_USER,運行這個實例應該可以看到這樣的登錄界面:

這個界面就是Spring Security為我們提供的登陸界面;
上面這個實例太簡單了,在現實項目中基本不會這么用,比如項目如有如下需求:
1.自定義登錄界面;
2.用Ajax方式登錄驗證;
3.用數據庫記錄用戶信息,進行登錄驗證;
4.用MD5方式密碼加密;
OK 接下來我們先來看看
自定義登錄界面的配置實例吧!
1.修改AppSecurity.xml中的http項,如下:
1 <http auto-config="true"> 2 <intercept-url pattern="/login.jsp" filters="none" /> 3 <intercept-url pattern="/*" access="ROLE_USER" /> 4 <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true" default-target-url="/index.jsp"/> 5 </http>
login-page:當用戶登錄時顯示自定義登錄頁面
authentication-failure-url:登錄失敗時跳轉到哪個頁面
default-target-url:登錄成功后跳轉到哪個頁面
這樣就把默認的登錄界面指向了login.jsp了,並且配置了出錯后的指向路徑和默認跳轉路徑等信息,當然這里的login.jsp需要任何人都可以訪問,不然的話會造成循環調用
authentication-failure-url:登錄失敗時跳轉到哪個頁面
default-target-url:登錄成功后跳轉到哪個頁面
2.設計login.jsp,關鍵代碼如下:
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>登陸界面</title>
- </head>
- <body>
- <h3>歡迎登陸</h3>
- <form action='/ctosii_middle/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 colspan='2'><input name="submit" type="submit" value="登陸"/></td></tr>
- </table>
- </form>
- </body>
- </html>

2.用ajax的方式實現的登錄驗證
Spring Security默認的是登陸驗證通過用跳轉的方式,但是在實際應用中很多應用的登錄界面需要用到ajax的方式來實現登陸驗證
1.修改AppSecurity.xml中的http項,如下:
1 <http auto-config="true"> 2 <intercept-url pattern="/login**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 3 <intercept-url pattern="/**/*.js" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 4 <intercept-url pattern="/**" access="ROLE_USER" /> 5 <form-login login-page="/login.jsp" authentication-failure-url="/login_fail.do" default-target-url="/login_success.do"/> 6 </http>
這里配置了兩個路徑失敗后的調用路徑和成功后的調用路徑。利用這兩個路徑可以實現ajax登陸。
在login_fail.do和login_success.do中可以輸出登陸失敗、成功的消息
2.Login.jsp修改如下:
1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 4 <script type="text/javascript" src="js/jquery-last.min.js"></script> 5 <script type="text/javascript"> 6 function doLogin(){ 7 var url = "/ctosii_middle/j_spring_security_check"; 8 var username= $("input[name='j_username']").val(); 9 var password= $("input[name='j_password']").val(); 10 $.ajax({ 11 url:url, 12 type:"POST", 13 data:"j_username="+username+"&j_password="+password, 14 success: function(data){ 15 $("#results").text(data); 16 } 17 }); 18 } 19 </script> 20 21 22 <title>登陸界面</title> 23 </head> 24 <body> 25 <h3>歡迎登陸</h3> 26 <form> 27 <table> 28 <tr><td>用戶名:</td><td><input type='text' name='j_username' value=''></td></tr> 29 <tr><td>密 碼:</td><td><input type='password' name='j_password'/></td></tr> 30 <tr><td colspan='2'><input name="submit" type="button" onclick="doLogin()" value="登陸"/></td></tr> 31 </table> 32 <div id="results"></div> 33 </form> 34 </body> 35 </html>
3.用數據庫記錄用戶信息,進行登錄驗證
上面的兩個例子都是用了硬編碼的方式驗證用戶信息,而實際項目中肯定是會把用戶信息存到數據庫中的,最典型的就是建users,role,user_role這三張表:
users:
DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(20) CHARACTER SET utf8 NOT NULL, `password` varchar(100) NOT NULL, `enabled` varchar(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
role:
1 DROP TABLE IF EXISTS `role`; 2 CREATE TABLE `role` ( 3 `id` int(11) NOT NULL AUTO_INCREMENT, 4 `name` varchar(100) CHARACTER SET utf8 NOT NULL, 5 `description` varchar(255) CHARACTER SET utf8 DEFAULT NULL, 6 `enabled` tinyint(1) DEFAULT NULL, 7 PRIMARY KEY (`id`), 8 UNIQUE KEY `rolename_index` (`name`) USING BTREE 9 ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
user_role:
DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(20) CHARACTER SET utf8 NOT NULL, `password` varchar(100) NOT NULL, `enabled` varchar(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
然后執行Sql插入數據:
INSERT INTO `users` VALUES ('0', 'xiakan', 'xiakan', '1'); INSERT INTO `role` VALUES ('1', 'user', '用戶角色', 1); INSERT INTO `role` VALUES ('2', 'admin', '管理員角色', 1); INSERT INTO `user_role` VALUES ('1', '1', '0');
2.修改AppSecurity.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans:beans xmlns="http://www.springframework.org/schema/security" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:beans="http://www.springframework.org/schema/beans" 5 xsi:schemaLocation=" 6 http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/security 9 http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 10 11 <http auto-config="true"> 12 <intercept-url pattern="/login**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 13 <intercept-url pattern="/**/*.js" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 14 <intercept-url pattern="/**" access="ROLE_USER" /> 15 <form-login login-page="/login.jsp" authentication-failure-url="/login_fail.do" default-target-url="/login_success.do"/> 16 </http> 17 18 <beans:bean id="userDetailsService" class="com.xk.security.UserDetailServiceImpl" /> 19 20 <authentication-manager alias="authenticationManager"> 21 <authentication-provider user-service-ref="userDetailsService" /> 22 </authentication-manager> 23 </beans:beans>
我們添加了一個Bean:com.xk.security.UserDetailServiceImpl,這個bean的代碼如下:
1 package com.xk.security; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.security.core.GrantedAuthority; 8 import org.springframework.security.core.authority.SimpleGrantedAuthority; 9 import org.springframework.security.core.userdetails.UserDetails; 10 import org.springframework.security.core.userdetails.UserDetailsService; 11 import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 13 import com.xk.dao.IUserManager; 14 import com.xk.item.Role; 15 import com.xk.item.User; 16 17 public class UserDetailServiceImpl implements UserDetailsService{ 18 @Autowired 19 private IUserManager userManager = null; 20 public UserDetailServiceImpl(){ 21 } 22 public IUserManager getUserManager() { 23 return userManager; 24 } 25 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 26 User user = userManager.search(username); 27 if (user==null) 28 throw new UsernameNotFoundException(username+" not exist!"); 29 List<GrantedAuthority> authsList = new ArrayList<GrantedAuthority>(); 30 for (Role role:userManager.getRoles(user)) { 31 authsList.add(new SimpleGrantedAuthority(role.getName())); 32 } 33 boolean accountNonExpired = true; 34 boolean credentialsNonExpired = true; 35 boolean accountNonLocked = true; 36 37 UserDetails userdetails = new org.springframework.security.core.userdetails.User(user.getUsername(), user 38 .getPassword(),user.isEnabled(), accountNonExpired, credentialsNonExpired, accountNonLocked, authsList); 39 40 return userdetails; 41 } 42 }
用剛剛的insert到數據庫的用戶信息,就可以看到如下界面:
4.用MD5方式密碼加密;
這里的數據庫中用了明碼的方式來存儲用戶密碼,這樣對用戶來說是很不安全的,前段時間各大網站的密碼泄露事件就是因為用了明文存儲用戶密碼,為了加密用戶的密碼,這里我們可以用MD5的方式:
1.修改AppSecurity.xml:
其實也可以用js做好加密后post到服務器,這樣更安全!