将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程
授權(quán)即訪問控制,它將判斷用戶在應(yīng)用程序中對資源是否擁有相應(yīng)的訪問權(quán)限。?
如,判斷一個用戶有查看頁面的權(quán)限,編輯數(shù)據(jù)的權(quán)限,擁有某一按鈕的權(quán)限等等。?
?
一、用戶權(quán)限模型
為實(shí)現(xiàn)一個較為靈活的用戶權(quán)限數(shù)據(jù)模型,通常把用戶信息單獨(dú)用一個實(shí)體表示,用戶權(quán)限信息用兩個實(shí)體表示。
?
?
權(quán)限聲明及粒度?
Shiro權(quán)限聲明通常是使用以冒號分隔的表達(dá)式。就像前文所講,一個權(quán)限表達(dá)式可以清晰的指定資源類型,允許的操作。同時,Shiro權(quán)限表達(dá)式支持簡單的通配符,可以更加靈活的進(jìn)行權(quán)限設(shè)置。?
下面以實(shí)例來說明權(quán)限表達(dá)式。?
可查詢用戶數(shù)據(jù)?
User:view?
可查詢或編輯用戶數(shù)據(jù)?
User:view,edit?
可對用戶數(shù)據(jù)進(jìn)行所有操作?
User:*或 user?
可編輯id為123的用戶數(shù)據(jù)?
User:edit:123?
?
授權(quán)處理過程
認(rèn)證通過后接受 Shiro 授權(quán)檢查,授權(quán)驗(yàn)證時,需要判斷當(dāng)前角色是否擁有該權(quán)限。
只有授權(quán)通過,才可以訪問受保護(hù) URL 對應(yīng)的資源,否則跳轉(zhuǎn)到“未經(jīng)授權(quán)頁面”。
如果我們自定義Realm實(shí)現(xiàn),比如我后面的例子中,自定義了ShiroDbRealm類,當(dāng)訪問ShiroDbRealm.doGetAuthorizationInfo()進(jìn)行授權(quán)。
@Controller @RequestMapping(value = "/user") public class UserController {@Resource(name="userService") private IUserService userService;/*** 測試權(quán)限* 只有擁有 user:create權(quán)限,才能進(jìn)行注冊* @param user* @return*/ @RequestMapping(value = "/register") @ResponseBody @RequiresPermissions("user:create") public boolean register(User user){ return userService.register(user); }?
?
二、授權(quán)實(shí)現(xiàn)?
Shiro支持三種方式實(shí)現(xiàn)授權(quán)過程:?
- 編碼實(shí)現(xiàn)
- 注解實(shí)現(xiàn)
- JSP Taglig實(shí)現(xiàn)
?
1、基于編碼的授權(quán)實(shí)現(xiàn)?
1、基于權(quán)限對象的實(shí)現(xiàn)?
創(chuàng)建org.apache.shiro.authz.Permission的實(shí)例,將該實(shí)例對象作為參數(shù)傳遞給Subject.isPermitted()進(jìn)行驗(yàn)證。?
? ? ??
Permission printPermission = new PrinterPermission("laserjet4400n", "print"); Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted(printPermission)) { //show the Print button } else { //don't show the button? Grey it out? }?
?
2、基于字符串的實(shí)現(xiàn)?
相比笨重的基于對象的實(shí)現(xiàn)方式,基于字符串的實(shí)現(xiàn)便顯得更加簡潔。?
? ? ? ?
Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted("printer:print:laserjet4400n")) { //show the Print button } else { //don't show the button? Grey it out? }?
使用冒號分隔的權(quán)限表達(dá)式是org.apache.shiro.authz.permission.WildcardPermission默認(rèn)支持的實(shí)現(xiàn)方式。?
這里分別代表了資源類型:操作:資源ID?
?
2、基于注解的授權(quán)實(shí)現(xiàn)?
Shiro注解支持AspectJ、Spring、Google-Guice等,可根據(jù)應(yīng)用進(jìn)行不同的配置。?
?
相關(guān)的注解:?
@RequiresAuthentication?
可以用戶類/屬性/方法,用于表明當(dāng)前用戶需是經(jīng)過認(rèn)證的用戶。??
? ? ? ??
@RequiresAuthentication public void updateAccount(Account userAccount) { //this method will only be invoked by a //Subject that is guaranteed authenticated ... }?
@RequiresPermissions?
當(dāng)前用戶需擁有制定權(quán)限?
? ? ? ?
@RequiresPermissions("account:create") public void createAccount(Account account) { //this method will only be invoked by a Subject //that is permitted to create an account ... }
?
?
3、基于JSP?TAG的授權(quán)實(shí)現(xiàn)?
Shiro提供了一套JSP標(biāo)簽庫來實(shí)現(xiàn)頁面級的授權(quán)控制。?
在使用Shiro標(biāo)簽庫前,首先需要在JSP引入shiro標(biāo)簽:?
hasRole標(biāo)簽?
驗(yàn)證當(dāng)前用戶是否屬于該角色
?
<shiro:hasRole name="administrator"> <a href="admin.jsp">Administer the system</a> </shiro:hasRole>?
hasPermission標(biāo)簽?
驗(yàn)證當(dāng)前用戶是否擁有制定權(quán)限?
?
<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission>?
三、Shiro授權(quán)的內(nèi)部處理機(jī)制?
?
1、在應(yīng)用程序中調(diào)用授權(quán)驗(yàn)證方法(Subject的isPermitted*或hasRole*等)?
2、Sbuject會委托應(yīng)用程序設(shè)置的securityManager實(shí)例調(diào)用相應(yīng)的isPermitted*或hasRole*方法。?
3、接下來SecurityManager會委托內(nèi)置的Authorizer的實(shí)例(默認(rèn)是ModularRealmAuthorizer類的實(shí)例,類似認(rèn)證實(shí)例)調(diào)用相應(yīng)的授權(quán)方法。?
4、每一個Realm將檢查是否實(shí)現(xiàn)了相同的Authorizer 接口。然后,將調(diào)用Reaml自己的相應(yīng)的授權(quán)驗(yàn)證方法。?
?
四、授權(quán)代碼
UserController:處理用戶登錄后的請求(注冊)
? ??
package org.shiro.demo.controller;import javax.annotation.Resource;import org.apache.shiro.authz.annotation.RequiresPermissions;import org.apache.shiro.authz.annotation.RequiresRoles;import org.shiro.demo.entity.User;import org.shiro.demo.service.IUserService;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@RequestMapping(value = "/user")public class UserController {@Resource(name="userService")private IUserService userService;/*** 測試權(quán)限* 只有擁有 user:create 權(quán)限,才能進(jìn)行注冊* @param user* @return*/@RequestMapping(value = "/register")@ResponseBody@RequiresPermissions("user:create")public boolean register(User user){return userService.register(user);}/*** 測試角色* 只有擁有 administrator 角色,才能跳轉(zhuǎn)到register頁面* @return*/@RequestMapping(value = "/toRegister")@RequiresRoles("administrator")public String toRegister(){return "/system/user/register";}}?
?
ShiroDbRealm:自定義的指定Shiro驗(yàn)證用戶授權(quán)的類
packageorg.shiro.demo.service.realm;importjava.util.ArrayList; importjava.util.List;importjavax.annotation.Resource;importorg.apache.commons.lang.StringUtils; importorg.apache.shiro.authc.AuthenticationException; importorg.apache.shiro.authc.AuthenticationInfo; importorg.apache.shiro.authc.AuthenticationToken; importorg.apache.shiro.authc.SimpleAuthenticationInfo; importorg.apache.shiro.authc.UsernamePasswordToken; importorg.apache.shiro.authz.AuthorizationException; importorg.apache.shiro.authz.AuthorizationInfo; importorg.apache.shiro.authz.SimpleAuthorizationInfo; importorg.apache.shiro.realm.AuthorizingRealm; importorg.apache.shiro.subject.PrincipalCollection; importorg.shiro.demo.entity.Permission; importorg.shiro.demo.entity.Role; importorg.shiro.demo.entity.User; importorg.shiro.demo.service.IUserService;/*** 自定義的指定Shiro驗(yàn)證用戶登錄的類* @author TCH**/ publicclass ShiroDbRealm extends AuthorizingRealm{//@Resource(name="userService") privateIUserService userService;publicvoid setUserService(IUserService userService) { this.userService= userService; }/*** 為當(dāng)前登錄的Subject授予角色和權(quán)限* @see 經(jīng)測試:本例中該方法的調(diào)用時機(jī)為需授權(quán)資源被訪問時* @see經(jīng)測試:并且每次訪問需授權(quán)資源時都會執(zhí)行該方法中的邏輯,這表明本例未啟用AuthorizationCache* @seeweb層可以有shiro的緩存,dao層可以配有hibernate的緩存(后面介紹)*/ protectedAuthorizationInfo doGetAuthorizationInfo( PrincipalCollectionprincipals) {//獲取當(dāng)前登錄的用戶名,等價(jià)于(String)principals.fromRealm(this.getName()).iterator().next() Stringaccount = (String) super.getAvailablePrincipal(principals);List<String>roles = new ArrayList<String>(); List<String>permissions = new ArrayList<String>();//從數(shù)據(jù)庫中獲取當(dāng)前登錄用戶的詳細(xì)信息 Useruser = userService.getByAccount(account);if(user!= null){ //實(shí)體類User中包含有用戶角色的實(shí)體類信息 if(user.getRoles() != null && user.getRoles().size() > 0) { //獲取當(dāng)前登錄用戶的角色 for(Role role : user.getRoles()) { roles.add(role.getName());//實(shí)體類Role中包含有角色權(quán)限的實(shí)體類信息 if(role.getPmss() != null && role.getPmss().size() > 0) {//獲取權(quán)限 for(Permission pmss : role.getPmss()) { if(!StringUtils.isEmpty(pmss.getPermission())){ permissions.add(pmss.getPermission()); } } } } } }else{ thrownew AuthorizationException(); }//為當(dāng)前用戶設(shè)置角色和權(quán)限 SimpleAuthorizationInfoinfo = new SimpleAuthorizationInfo(); info.addRoles(roles);info.addStringPermissions(permissions);returninfo;}}?
轉(zhuǎn)載于:https://www.cnblogs.com/hanxue112253/p/3850546.html
總結(jié)
以上是生活随笔為你收集整理的将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cocos2d-x3.0游戏实例《不要救
- 下一篇: Eval绑定日期时,修改日期显示的格式