前言
本文主要講解的知識點有以下:
- 權限管理的基礎知識
- 模型
- 粗粒度和細粒度的概念
- 回顧URL攔截的實現(xiàn)
- Shiro的介紹與簡單入門
一、Shiro基礎知識
在學習Shiro這個框架之前,首先我們要先了解Shiro需要的基礎知識:權限管理
1.1什么是權限管理?
只要有用戶參與的系統(tǒng)一般都要有權限管理,權限管理實現(xiàn)對用戶訪問系統(tǒng)的控制,按照安全規(guī)則或者安全策略控制用戶可以訪問而且只能訪問自己被授權的資源。
對權限的管理又分為兩大類別:
- 用戶認證
- 用戶授權
1.1.1用戶認證
用戶認證,用戶去訪問系統(tǒng),系統(tǒng)要驗證用戶身份的合法性
最常用的用戶身份驗證的方法:1、用戶名密碼方式、2、指紋打卡機、3、基于證書驗證方法。。系統(tǒng)驗證用戶身份合法,用戶方可訪問系統(tǒng)的資源。
舉個例子:
- 當我們輸入了自己的淘寶的賬戶和密碼,才能打開購物車
用戶認證的流程:
- 判斷該資源能否不認證就能訪問【登陸頁面、首頁】
- 如果該資源需要認證后才能訪問,那么判斷該訪問者是否認證了
- 如果還沒有認證,那么需要返回到【登陸頁面】進行認證
- 認證通過后才能訪問資源
這里寫圖片描述
從用戶認證我們可以抽取出這么幾個概念
- subject主體:理解為用戶,可能是程序,都要去訪問系統(tǒng)的資源,系統(tǒng)需要對subject進行身份認證
- principal身份信息:通常是唯一的,一個主體還有多個身份信息,但是都有一個主身份信息(primary principal)【我們可以選擇身份證認證、學生證認證等等都是我們的身份信息】
- credential憑證信息:可以是密碼 、證書、指紋。
總結:主體在進行身份認證時需要提供身份信息和憑證信息。
1.1.2用戶授權
用戶授權,簡單理解為訪問控制,在用戶認證通過后,系統(tǒng)對用戶訪問資源進行控制,用戶具有資源的訪問權限方可訪問。
用戶授權的流程
- 到達了用戶授權環(huán)節(jié),當然是需要用戶認證之后了
- 用戶訪問資源,系統(tǒng)判斷該用戶是否有權限去操作該資源
- 如果該用戶有權限才能夠訪問,如果沒有權限就不能訪問了
這里寫圖片描述
授權的過程可以簡單理解為:主體認證之后,系統(tǒng)進行訪問控制
subject必須具備資源的訪問權限才可訪問該資源..
權限/許可(permission) :針對資源的權限或許可,subject具有permission訪問資源,如何訪問/操作需要定義permission,權限比如:用戶添加、用戶修改、商品刪除
資源可以分為兩種
- 資源類型:系統(tǒng)的用戶信息就是資源類型,相當于java類。
- 資源實例:系統(tǒng)中id為001的用戶就是資源實例,相當于new的java對象。
1.2權限管理模型
一般地,我們可以抽取出這么幾個模型:
- 主體(賬號、密碼)
- 資源(資源名稱、訪問地址)
- 權限(權限名稱、資源id)
- 角色(角色名稱)
- 角色和權限關系(角色id、權限id)
- 主體和角色關系(主體id、角色id)
這里寫圖片描述
通常企業(yè)開發(fā)中將資源和權限表合并為一張權限表,如下:
- 資源(資源名稱、訪問地址)
- 權限(權限名稱、資源id)
合并為:
- 權限(權限名稱、資源名稱、資源訪問地址)
這里寫圖片描述
1.3分配權限
用戶需要分配相應的權限才可訪問相應的資源。權限是對于資源的操作許可。
通常給用戶分配資源權限需要將權限信息持久化,比如存儲在關系數(shù)據(jù)庫中。把用戶信息、權限管理、用戶分配的權限信息寫到數(shù)據(jù)庫(權限數(shù)據(jù)模型)
1.3.1基于角色訪問控制
RBAC(role based access control),基于角色的訪問控制。
//如果該user是部門經(jīng)理則可以訪問if中的代碼if(user.hasRole(\’部門經(jīng)理\’)){ //系統(tǒng)資源內(nèi)容 //用戶報表查看}
角色針對人劃分的,人作為用戶在系統(tǒng)中屬于活動內(nèi)容,如果該 角色可以訪問的資源出現(xiàn)變更,需要修改你的代碼了,
if(user.hasRole(\’部門經(jīng)理\’) || user.hasRole(\’總經(jīng)理\’) ){ //系統(tǒng)資源內(nèi)容 //用戶報表查看}
基于角色的訪問控制是不利于系統(tǒng)維護(可擴展性不強)。
1.3.2基于資源的訪問控制
RBAC(Resource based access control),基于資源的訪問控制。
資源在系統(tǒng)中是不變的,比如資源有:類中的方法,頁面中的按鈕。
對資源的訪問需要具有permission權限,代碼可以寫為:if(user.hasPermission (\’用戶報表查看(權限標識符)\’)){ //系統(tǒng)資源內(nèi)容 //用戶報表查看}
建議使用基于資源的訪問控制實現(xiàn)權限管理。
二、 粗粒度和細粒度權限
細粒度權限管理:對資源實例的權限管理。資源實例就資源類型的具體化,比如:用戶id為001的修改連接,1110班的用戶信息、行政部的員工。細粒度權限管理就是數(shù)據(jù)級別的權限管理。
粗粒度權限管理比如:超級管理員可以訪問戶添加頁面、用戶信息等全部頁面。部門管理員可以訪問用戶信息頁面包括 頁面中所有按鈕。
粗粒度和細粒度例子:
系統(tǒng)有一個用戶列表查詢頁面,對用戶列表查詢分權限,如果粗顆粒管理,張三和李四都有用戶列表查詢的權限,張三和李四都可以訪問用戶列表查詢。進一步進行細顆粒管理,張三(行政部)和李四(開發(fā)部)只可以查詢自己本部門的用戶信息。張三只能查看行政部 的用戶信息,李四只能查看開發(fā)部門的用戶信息。細粒度權限管理就是數(shù)據(jù)級別的權限管理。
2.1如何實現(xiàn)粗粒度權限管理?
粗粒度權限管理比較容易將權限管理的代碼抽取出來在系統(tǒng)架構級別統(tǒng)一處理。比如:通過springmvc的攔截器實現(xiàn)授權。
對細粒度權限管理在數(shù)據(jù)級別是沒有共性可言,針對細粒度權限管理就是系統(tǒng)業(yè)務邏輯的一部分,在業(yè)務層去處理相對比較簡單
比如:部門經(jīng)理只查詢本部門員工信息,在service接口提供一個部門id的參數(shù),controller中根據(jù)當前用戶的信息得到該 用戶屬于哪個部門,調(diào)用service時將部門id傳入service,實現(xiàn)該用戶只查詢本部門的員工。
2.1.1基于URL攔截
基于url攔截的方式實現(xiàn)在實際開發(fā)中比較常用的一種方式。
對于web系統(tǒng),通過filter過慮器實現(xiàn)url攔截,也可以springmvc的攔截器實現(xiàn)基于url的攔截。
2.2.2使用權限管理框架實現(xiàn)
對于粗粒度權限管理,建議使用優(yōu)秀權限管理框架來實現(xiàn),節(jié)省開發(fā)成功,提高開發(fā)效率。
shiro就是一個優(yōu)秀權限管理框架。
三、回顧URL攔截
我們在學習的路途上也是使用過幾次URL對權限進行攔截的
當時我們做了權限的增刪該查的管理系統(tǒng),但是在權限表中是沒有把資源添加進去,我們使用的是Map集合來進行替代的。
http://blog.csdn.net/hon_3y/article/details/61926175
隨后,我們學習了動態(tài)代理和注解,我們也做了一個基于注解的攔截
- 在Controller得到service對象的時候,service工廠返回的是一個動態(tài)代理對象回去
- Controller拿著代理對象去調(diào)用方法,代理對象就會去解析該方法上是否有注解
- 如果有注解,那么就需要我們進行判斷該主體是否認證了,如果認證了就判斷該主體是否有權限
- 當我們解析出該主體的權限和我們注解的權限是一致的時候,才放行!
http://blog.csdn.net/hon_3y/article/details/70767050
流程:
這里寫圖片描述
3.1認證的JavaBean
我們之前認證都是放在默認的Javabean對象上的,現(xiàn)在既然我們準備學Shiro了,我們就得專業(yè)一點,弄一個專門存儲認證信息的JavaBean
/** * 用戶身份信息,存入session 由于tomcat將session會序列化在本地硬盤上,所以使用Serializable接口 * * @author Thinkpad * */public class ActiveUser implements java.io.Serializable { private String userid;//用戶id(主鍵) private String usercode;// 用戶賬號 private String username;// 用戶名稱 private List<SysPermission> menus;// 菜單 private List<SysPermission> permissions;// 權限 // 省略get和set方法}
認證的服務
@Override public ActiveUser authenticat(String userCode, String password) throws Exception { /** 認證過程: 根據(jù)用戶身份(賬號)查詢數(shù)據(jù)庫,如果查詢不到用戶不存在 對輸入的密碼 和數(shù)據(jù)庫密碼 進行比對,如果一致,認證通過 */ //根據(jù)用戶賬號查詢數(shù)據(jù)庫 SysUser sysUser = this.findSysUserByUserCode(userCode); if(sysUser == null){ //拋出異常 throw new CustomException(\”用戶賬號不存在\”); } //數(shù)據(jù)庫密碼 (md5密碼 ) String password_db = sysUser.getPassword(); //對輸入的密碼 和數(shù)據(jù)庫密碼 進行比對,如果一致,認證通過 //對頁面輸入的密碼 進行md5加密 String password_input_md5 = new MD5().getMD5ofStr(password); if(!password_input_md5.equalsIgnoreCase(password_db)){ //拋出異常 throw new CustomException(\”用戶名或密碼 錯誤\”); } //得到用戶id String userid = sysUser.getId(); //根據(jù)用戶id查詢菜單 List<SysPermission> menus =this.findMenuListByUserId(userid); //根據(jù)用戶id查詢權限url List<SysPermission> permissions = this.findPermissionListByUserId(userid); //認證通過,返回用戶身份信息 ActiveUser activeUser = new ActiveUser(); activeUser.setUserid(sysUser.getId()); activeUser.setUsercode(userCode); activeUser.setUsername(sysUser.getUsername());//用戶名稱 //放入權限范圍的菜單和url activeUser.setMenus(menus); activeUser.setPermissions(permissions); return activeUser; }
Controller處理認證,如果身份認證成功,那么把認證信息存儲在Session中
@requestMapping(\”/login\”) public String login(HttpSession session, String randomcode,String usercode,String password)throws Exception{ //校驗驗證碼,防止惡性攻擊 //從session獲取正確驗證碼 String validateCode = (String) session.getAttribute(\”validateCode\”); //輸入的驗證和session中的驗證進行對比 if(!randomcode.equals(validateCode)){ //拋出異常 throw new CustomException(\”驗證碼輸入錯誤\”); } //調(diào)用service校驗用戶賬號和密碼的正確性 ActiveUser activeUser = sysService.authenticat(usercode, password); //如果service校驗通過,將用戶身份記錄到session session.setAttribute(\”activeUser\”, activeUser); //重定向到商品查詢頁面 return \”redirect:/first.action\”; }
身份認證攔截器
//在執(zhí)行handler之前來執(zhí)行的 //用于用戶認證校驗、用戶權限校驗 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //得到請求的url String url = request.getRequestURI(); //判斷是否是公開 地址 //實際開發(fā)中需要公開 地址配置在配置文件中 //從配置中取逆名訪問url List<String> open_urls = ResourcesUtil.gekeyList(\”anonymousURL\”); //遍歷公開 地址,如果是公開 地址則放行 for(String open_url:open_urls){ if(url.indexOf(open_url)>=0){ //如果是公開 地址則放行 return true; } } //判斷用戶身份在session中是否存在 HttpSession session = request.getSession(); ActiveUser activeUser = (ActiveUser) session.getAttribute(\”activeUser\”); //如果用戶身份在session中存在放行 if(activeUser!=null){ return true; } //執(zhí)行到這里攔截,跳轉(zhuǎn)到登陸頁面,用戶進行身份認證 request.getRequestDispatcher(\”/WEB-INF/jsp/login.jsp\”).forward(request, response); //如果返回false表示攔截不繼續(xù)執(zhí)行handler,如果返回true表示放行 return false; }
授權攔截器
//在執(zhí)行handler之前來執(zhí)行的 //用于用戶認證校驗、用戶權限校驗 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //得到請求的url String url = request.getRequestURI(); //判斷是否是公開 地址 //實際開發(fā)中需要公開 地址配置在配置文件中 //從配置中取逆名訪問url List<String> open_urls = ResourcesUtil.gekeyList(\”anonymousURL\”); //遍歷公開 地址,如果是公開 地址則放行 for(String open_url:open_urls){ if(url.indexOf(open_url)>=0){ //如果是公開 地址則放行 return true; } } //從配置文件中獲取公共訪問地址 List<String> common_urls = ResourcesUtil.gekeyList(\”commonURL\”); //遍歷公用 地址,如果是公用 地址則放行 for(String common_url:common_urls){ if(url.indexOf(common_url)>=0){ //如果是公開 地址則放行 return true; } } //獲取session HttpSession session = request.getSession(); ActiveUser activeUser = (ActiveUser) session.getAttribute(\”activeUser\”); //從session中取權限范圍的url List<SysPermission> permissions = activeUser.getPermissions(); for(SysPermission sysPermission:permissions){ //權限的url String permission_url = sysPermission.getUrl(); if(url.indexOf(permission_url)>=0){ //如果是權限的url 地址則放行 return true; } } //執(zhí)行到這里攔截,跳轉(zhuǎn)到無權訪問的提示頁面 request.getRequestDispatcher(\”/WEB-INF/jsp/refuse.jsp\”).forward(request, response); //如果返回false表示攔截不繼續(xù)執(zhí)行handler,如果返回true表示放行 return false; }
攔截器配置:
<!–攔截器 –> <mvc:interceptors> <mvc:interceptor> <!– 用戶認證攔截 –> <mvc:mapping path=\”/**\” /> <bean class=\”cn.itcast.ssm.controller.interceptor.Logininterceptor\”></bean> </mvc:interceptor> <mvc:interceptor> <!– 授權攔截 –> <mvc:mapping path=\”/**\” /> <bean class=\”cn.itcast.ssm.controller.interceptor.PermissionInterceptor\”></bean> </mvc:interceptor> </mvc:interceptors>
四、什么是Shiro
shiro是apache的一個開源框架,是一個權限管理的框架,實現(xiàn) 用戶認證、用戶授權。
spring中有spring security (原名Acegi),是一個權限框架,它和spring依賴過于緊密,沒有shiro使用簡單。
shiro不依賴于spring,shiro不僅可以實現(xiàn) web應用的權限管理,還可以實現(xiàn)c/s系統(tǒng),分布式系統(tǒng)權限管理,shiro屬于輕量框架,越來越多企業(yè)項目開始使用shiro。
Shiro架構:
這里寫圖片描述
- subject:主體,可以是用戶也可以是程序,主體要訪問系統(tǒng),系統(tǒng)需要對主體進行認證、授權。
- securityManager:安全管理器,主體進行認證和授權都 是通過securityManager進行。
- authenticator:認證器,主體進行認證最終通過authenticator進行的。
- authorizer:授權器,主體進行授權最終通過authorizer進行的。
- sessionManager:web應用中一般是用web容器對session進行管理,shiro也提供一套session管理的方式。
- SessionDao: 通過SessionDao管理session數(shù)據(jù),針對個性化的session數(shù)據(jù)存儲需要使用sessionDao。
- cache Manager:緩存管理器,主要對session和授權數(shù)據(jù)進行緩存,比如將授權數(shù)據(jù)通過cacheManager進行緩存管理,和ehcache整合對緩存數(shù)據(jù)進行管理。
- realm:域,領域,相當于數(shù)據(jù)源,通過realm存取認證、授權相關數(shù)據(jù)。
cryptography:密碼管理,提供了一套加密/解密的組件,方便開發(fā)。比如提供常用的散列、加/解密等功能。
- 比如md5散列算法。
五、為什么使用Shiro
我們在使用URL攔截的時候,要將所有的URL都配置起來,繁瑣、不易維護
而我們的Shiro實現(xiàn)系統(tǒng)的權限管理,有效提高開發(fā)效率,從而降低開發(fā)成本。
六、Shiro認證
6.1導入jar包
我們使用的是Maven的坐標就行了
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.2.3</version> </dependency>
當然了,我們也可以把Shiro相關的jar包全部導入進去
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.2.3</version></dependency>
6.2Shiro認證流程
這里寫圖片描述
6.2.1通過配置文件創(chuàng)建工廠
這里寫圖片描述
// 用戶登陸和退出 @Test public void testLoginAndLogout() { // 創(chuàng)建securityManager工廠,通過ini配置文件創(chuàng)建securityManager工廠 factory<SecurityManager> factory = new IniSecurityManagerFactory( \”classpath:shiro-first.ini\”); // 創(chuàng)建SecurityManager SecurityManager securityManager = factory.getInstance(); // 將securityManager設置當前的運行環(huán)境中 SecurityUtils.setSecurityManager(securityManager); // 從SecurityUtils里邊創(chuàng)建一個subject Subject subject = SecurityUtils.getSubject(); // 在認證提交前準備token(令牌) // 這里的賬號和密碼 將來是由用戶輸入進去 UsernamePasswordToken token = new UsernamePasswordToken(\”zhangsan\”, \”111111\”); try { // 執(zhí)行認證提交 subject.login(token); } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 是否認證通過 boolean isAuthenticated = subject.isAuthenticated(); System.out.println(\”是否認證通過:\” isAuthenticated); // 退出操作 subject.logout(); // 是否認證通過 isAuthenticated = subject.isAuthenticated(); System.out.println(\”是否認證通過:\” isAuthenticated); }
這里寫圖片描述
6.3小結
ModularRealmAuthenticator作用進行認證,需要調(diào)用realm查詢用戶信息(在數(shù)據(jù)庫中存在用戶信息)
ModularRealmAuthenticator進行密碼對比(認證過程)。
realm:需要根據(jù)token中的身份信息去查詢數(shù)據(jù)庫(入門程序使用ini配置文件),如果查到用戶返回認證信息,如果查詢不到返回null。
6.4自定義realm
從第一個認證程序我們可以看見,我們所說的流程,是認證器去找realm去查詢我們相對應的數(shù)據(jù)。而默認的realm是直接去與配置文件來比對的,一般地,我們在開發(fā)中都是讓realm去數(shù)據(jù)庫中比對。
因此,我們需要自定義realm
這里寫圖片描述
public class CustomRealm extends AuthorizingRealm { // 設置realm的名稱 @Override public void setName(String name) { super.setName(\”customRealm\”); } // 用于認證 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // token是用戶輸入的 // 第一步從token中取出身份信息 String userCode = (String) token.getPrincipal(); // 第二步:根據(jù)用戶輸入的userCode從數(shù)據(jù)庫查詢 // …. // 如果查詢不到返回null //數(shù)據(jù)庫中用戶賬號是zhangsansan /*if(!userCode.equals(\”zhangsansan\”)){// return null; }*/ // 模擬從數(shù)據(jù)庫查詢到密碼 String password = \”111112\”; // 如果查詢到返回認證信息AuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( userCode, password, this.getName()); return simpleAuthenticationInfo; } // 用于授權 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // TODO Auto-generated method stub return null; }}
6.5配置realm
需要在shiro-realm.ini配置realm注入到securityManager中。
這里寫圖片描述
6.6測試自定義realm
同上邊的入門程序,需要更改ini配置文件路徑:
同上邊的入門程序,需要更改ini配置文件路徑:Factory<SecurityManager> factory = new IniSecurityManagerFactory( \”classpath:shiro-realm.ini\”);
6.7散列算法
我們?nèi)绻續(xù)d5,我們就會知道m(xù)d5是不可逆的,但是如果設置了一些安全性比較低的密碼:111111…即時是不可逆的,但還是可以通過暴力算法來得到md5對應的明文…
建議對md5進行散列時加salt(鹽),進行加密相當 于對原始密碼 鹽進行散列。
正常使用時散列方法:
- 在程序中對原始密碼 鹽進行散列,將散列值存儲到數(shù)據(jù)庫中,并且還要將鹽也要存儲在數(shù)據(jù)庫中。
測試:
public class MD5Test { public static void main(String[] args) { //原始 密碼 String source = \”111111\”; //鹽 String salt = \”qwerty\”; //散列次數(shù) int hashIterations = 2; //上邊散列1次:f3694f162729b7d0254c6e40260bf15c //上邊散列2次:36f2dfa24d0a9fa97276abbe13e596fc //構造方法中: //第一個參數(shù):明文,原始密碼 //第二個參數(shù):鹽,通過使用隨機數(shù) //第三個參數(shù):散列的次數(shù),比如散列兩次,相當 于md5(md5(\’\’)) Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations); String password_md5 = md5Hash.toString(); System.out.println(password_md5); //第一個參數(shù):散列算法 SimpleHash simpleHash = new SimpleHash(\”md5\”, source, salt, hashIterations); System.out.println(simpleHash.toString()); }}
6.8自定義realm支持md5
自定義realm
public class CustomRealmMd5 extends AuthorizingRealm { // 設置realm的名稱 @Override public void setName(String name) { super.setName(\”customRealmMd5\”); } // 用于認證 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // token是用戶輸入的 // 第一步從token中取出身份信息 String userCode = (String) token.getPrincipal(); // 第二步:根據(jù)用戶輸入的userCode從數(shù)據(jù)庫查詢 // …. // 如果查詢不到返回null // 數(shù)據(jù)庫中用戶賬號是zhangsansan /* * if(!userCode.equals(\”zhangsansan\”)){// return null; } */ // 模擬從數(shù)據(jù)庫查詢到密碼,散列值 String password = \”f3694f162729b7d0254c6e40260bf15c\”; // 從數(shù)據(jù)庫獲取salt String salt = \”qwerty\”; //上邊散列值和鹽對應的明文:111111 // 如果查詢到返回認證信息AuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( userCode, password, ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; } // 用于授權 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // TODO Auto-generated method stub return null; }}
配置文件:
這里寫圖片描述
測試:
// 自定義realm實現(xiàn)散列值匹配 @Test public void testCustomRealmMd5() { // 創(chuàng)建securityManager工廠,通過ini配置文件創(chuàng)建securityManager工廠 Factory<SecurityManager> factory = new IniSecurityManagerFactory( \”classpath:shiro-realm-md5.ini\”); // 創(chuàng)建SecurityManager SecurityManager securityManager = factory.getInstance(); // 將securityManager設置當前的運行環(huán)境中 SecurityUtils.setSecurityManager(securityManager); // 從SecurityUtils里邊創(chuàng)建一個subject Subject subject = SecurityUtils.getSubject(); // 在認證提交前準備token(令牌) // 這里的賬號和密碼 將來是由用戶輸入進去 UsernamePasswordToken token = new UsernamePasswordToken(\”zhangsan\”, \”222222\”); try { // 執(zhí)行認證提交 subject.login(token); } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 是否認證通過 boolean isAuthenticated = subject.isAuthenticated(); System.out.println(\”是否認證通過:\” isAuthenticated); }
七、總結
- 用戶認證和用戶授權是Shiro的基礎,用戶認證其實上就是登陸操作、用戶授權實際上就是對資源攔截的操作。
- 權限管理的模型一般我們都將資源放在權限表中進行管理起來。
- 我們可以基于角色攔截,也可以基于資源攔截。要是基于角色攔截的話,那么如果角色的權限發(fā)生變化了,那就需要修改代碼了。推薦使用基于資源進行攔截
- 這次URL攔截,我們使用一個JavaBean來封裝所有的認證信息。當用戶登陸了之后,我們就把用戶對菜單欄的訪問、對資源的訪問權限都封裝到該JavaBean中
- 當使用攔截器進行用戶認證的時候,我們只要判斷Session域有沒有JavaBen對象即可了。
- 當時候攔截器進行用戶授權的時候,我們要判斷JavaBean中的權限是否能夠訪問該資源。
- 以前URL攔截的方式需要把所有的URL都在數(shù)據(jù)庫進行管理。非常麻煩,不易維護。
- 我們希望Shiro去認證的時候是通過realm去數(shù)據(jù)庫查詢數(shù)據(jù)的。而我們reaml默認是查詢配置文件的數(shù)據(jù)的。
- 因此,我們需要自定義reaml,使得它是去數(shù)據(jù)庫查詢數(shù)據(jù)。只要繼承AuthorizingRealm類就行了。
- 當然了,自定義后的reaml也需要在配置文件中寫上我們的自定義reaml的位置的。
- 散列算法就是為了讓密碼不被別人給破解。我們可對原始的密碼加鹽再進行散列,這就加大了破解的難度了。
- 自定義的reaml也是支持散列算法的,相同的,還是需要我們在配置文件中配置一下就好了。
作者:Java3y原文:轉(zhuǎn)載自公眾號,Java3y,已獲作者授權
版權聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 舉報,一經(jīng)查實,本站將立刻刪除。