好,咱們往下看,接着就是應用咱們實際項目裏的自定義用戶權限了html
Java代碼 java
<security:authentication-manager> <security:authentication-provider user-service-ref="customUserDetailsService"> <security:password-encoder ref="passwordEncoder" /> </security:authentication-provider> </security:authentication-manager> <!-- 對密碼進行MD5編碼 --> <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" /> <bean id="customUserDetailsService" class="org.yzsoft.springmvcdemo.util.CustomUserDetailsService" />
首先是<security:authentication-manager>是指定咱們自定義的身份驗證策略,這裏咱們用customUserDetailsService這個bean,就是指向咱們CustomUserDetailsService.java這個類。而後<security:password-encoder>指定咱們密碼使用MD5進行編碼,調用Spring Security自帶的MD5加密類。固然,還有加鹽MD5或咱們本身寫的加密算法等安全性更加高的密碼策略。這個按項目實際使用配置吧。
web
而後看到咱們的CustomUserDetailsService.java算法
Java代碼 spring
package org.yzsoft.springmvcdemo.util; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.yzsoft.springmvcdemo.serviceimpl.UsersServiceImpl; import org.yzsoft.springmvcdemo.vo.TUsers; /** * 一個自定義的類用來和數據庫進行操做. 即之後咱們要經過數據庫保存權限.則須要咱們繼承UserDetailsService * * @author * */ public class CustomUserDetailsService implements UserDetailsService { protected static Logger logger = Logger.getLogger("service");//log4j,不用解釋了吧。。 @Autowired private UsersServiceImpl usersService; public UsersServiceImpl getUsersService() { return usersService; } public void setUsersService(UsersServiceImpl usersService) { this.usersService = usersService; } public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { UserDetails user = null; try { // 搜索數據庫以匹配用戶登陸名. // 咱們能夠經過dao使用Hibernate來訪問數據庫 System.out.println(username + " 用戶頁面輸入的用戶名"); TUsers tusers = this.usersService.findByUsername(username); System.out.println(tusers.getUsername() + " 數據庫取出的用戶名"); // Populate the Spring User object with details from the dbUser // Here we just pass the username, password, and access level // getAuthorities() will translate the access level to the correct // role type // 用戶名、密碼、是否啓用、是否被鎖定、是否過時、權限 user = new User(tusers.getUsername(), tusers.getPassword().toLowerCase(), true, true, true, true, getAuthorities(Integer.parseInt(tusers.getRole()))); } catch (Exception e) { logger.error("用戶信息錯誤!"); throw new UsernameNotFoundException("異常處理:檢索用戶信息未經過!"); } return user; } /** * 得到訪問角色權限列表 * * @param access * @return */ public Collection<GrantedAuthority> getAuthorities(Integer role) { System.out.println("取得的權限是 :" + role); List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); // 全部的用戶默認擁有ROLE_USER權限 if (role == 0) { System.out.println("普通用戶"); logger.debug("取得普通用戶權限-->"); authList.add(new GrantedAuthorityImpl("ROLE_USERS")); } // 若是參數role爲1.則擁有ROLE_ADMIN權限 if (role == 1) { logger.debug("取得ADMIN用戶權限-->"); authList.add(new GrantedAuthorityImpl("ROLE_ADMIN")); } System.out.println(authList.size()+" 權限列表長度"); return authList; } }
這裏就是把咱們從數據庫裏面取得的用戶權限和Spring Security的配置進行橋接,還記得上面配置文件裏的ROLE_ADMIN吧,就是從這裏來的,很奇怪的是,這個必須設置成ROLE_ 開頭纔有效。。鬱悶。。。數據庫
這裏我剛開始有一個疑惑,咱們看這2句apache
Java代碼 安全
TUsers tusers = this.usersService.findByUsername(username); user = new User(tusers.getUsername(), tusers.getPassword().toLowerCase(), true, true, true, true, getAuthorities(Integer.parseInt(tusers.getRole())));
這裏根本不須要用戶輸入的密碼,只要了用戶名,而後直接根據用戶名去取權限,就直接設置進Spring Security的User對象裏面去,我不由一身冷汗,這不至關於說有了用戶名就直接去查數據庫麼,並且是不用密碼的。。。。session
但通過查看官方文檔和網上的解釋,這才放心,原來是這樣的,Spring Security的確是直接根據用戶名去查,可是查得出來的Spring Security User對象以後,它會根據這個對象的屬性值去數據庫查詢與這個對象匹配的數據,咱們這裏設置的是(用戶名,密碼,是否啓用、是否被鎖定、是否過時、權限。。。),那麼若是數據庫存在這個對象,就返回真,不然返回假,這樣也就不用擔憂了,徹底可靠。就是咱們在前臺要作好限制,不能給用戶不輸密碼就訪問, 否則擠爆你數據庫鏈接。。。。。
mvc
最後登錄頁面index.jsp
Java代碼
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> 用戶登錄 <br> ${SPRING_SECURITY_LAST_EXCEPTION.message} <form action="j_spring_security_check" method="post"> USERNAME:<input type="text" name="j_username" value="${sessionScope['SPRING_SECURITY_LAST_USERNAME']}" /><br/> PASSWORD:<input type="password" name="j_password" value="" /><br/> <input type="checkbox" name="_spring_security_remember_me" />兩週以內沒必要登錄(這個功能沒有作的)<br/> <input type="submit"> </form> </body> </html>
這裏我仍是使用Spring Security默認的j_username和j_password,表單目標也用默認的j_spring_security_check,會默認跳到Spring Security進行攔截。其餘的應該不用解釋了吧。。。。
最後 ,咱們整理一下Spring Security的整個控制過程:
——>用戶登錄
——> <security:authentication-manager> 攔截
——>交給customUserDetailsService處理,而且聲明密碼採用MD5策略
——>根據輸入的用戶名去數據庫查這條記錄,驗證身份
——>取出該條記錄的用戶權限(鎖定、禁用、過時和實際權限等)
——>根據取得的權限列表去security:intercept-url匹配、受權,而後判斷是否放行。
這就完成了一整個的權限控制流程。
接下來咱們來測試一下看是否真的生效了:
一、測試匿名訪問頁面,直接地址欄訪問:
二、普通用戶登錄
三、而後訪問後臺管理頁面,跳回了登錄頁
四、管理員用戶登錄
退出後成功跳轉回登錄頁,點擊後退再執行其餘操做,這時候session已經註銷了的,不能執行,又跳回了登錄頁。是咱們想要的效果,OK,成功了。
好 了,Spring Security的簡單使用就講到這裏,其實這只是Spring Security的一小部分,並且這裏我尚未用權限表對用戶權限進行專門的管理,不少東西仍是用Spring Security 默認的,還有Spring Security CAS (單點登錄)以及更加高級的權限控制和更完善的Spring Security 配置,之後咱們再慢慢去研究吧。發現Spring Security 這個技術不只簡化了咱們的用戶權限管理,要知道咱們作管理系統的時候這是個大問題,也差很少顛覆了我一向以來用戶權限管理的觀念,可是掌握了這種思惟之 後,又發現,其實,程序並非只有一種實現方式,它激發了我寫程序時要去尋找多種解決方案的想法。學習的路上,就是要不斷推翻本身固有的思惟,去見識多種 新事物,纔能有進步。