shiro許可權筆記
shiro框架執行流程
認證:系統提供的用於識別使用者身份的功能,通常就是登入功能。----讓系統知道你是誰??
授權:系統提供的為使用者分配訪問系統某些功能的能力。----讓系統知道你能做什麼??
官網:http://shiro.apache.org/
shiro執行流程
Application Code:應用程式程式碼,由開發人員負責開發
Subject:主體,當前使用者
SecurityManager:安全管理器,由shiro框架提供,可以管理所有的主體
Realm:安全資料橋,類似於系統中的Dao,負責訪問安全資料(許可權、角色、使用者)
shiro框架核心功能
1、認證
2、授權
3、會話管理
4、加密
shiro框架提供的許可權控制方式
1、URL攔截
2、方法註解
3、頁面標籤
4、程式碼級別
涉及的jar包
攔截引數
Shiro 的預設Filter 對應的類
filter過濾器別名 |
描述 |
類路徑 |
anon |
匿名過濾器 |
|
authc |
認證後過濾器 |
|
perms |
許可權過濾器 |
org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port |
|
|
rest |
|
org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
noSessionCreation |
|
|
authcBasic |
|
org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
roles |
角色過濾器 |
|
ssl |
安全協議過濾器 |
|
user |
使用者過濾器 |
|
logout |
退出過濾器 |
anon: 例如/admins/**=anon 沒有引數,表示可以匿名使用。
authc: 例如/admins/user/**=authc表示需要認證(登入)才能使用,沒有引數
roles: 例如/admins/user/**=roles[admin],引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,當有多個引數時,例如admins/user/**=roles["admin,guest"],每個引數通過才算通過,相當於hasAllRoles()方法。
perms:例如/admins/user/**=perms[user:add:*],引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],當有多個引數時必須每個引數都通過才通過,想當於isPermitedAll()方法。
rest: 例如/admins/user/**=rest[user],根據請求的方法,相當於
/admins/user/**=perms[user:method] ,其中method為post,get,delete等。
port: 例如/admins/user/**=port[8081],當請求的url的埠不是8081是跳轉到schemal://serverName:8081?queryString,其中schmal是協議http或https等,serverName是你訪問的host,8081是url配置裡port的埠,queryString是你訪問的url裡的?號後面的引數。
authcBasic:例如/admins/user/**=authcBasic沒有引數表示httpBasic認證
ssl: 例如/admins/user/**=ssl沒有引數,表示安全的url請求,協議為https
user: 例如/admins/user/**=user沒有引數表示必須存在使用者,當登入操作時不做檢查
注:anon,authcBasic,auchc,user是認證過濾器,
perms,roles,ssl,rest,port是授權過濾器
/**代表所有子包都能匹配
web.xml配置
<!-- spring提供用於整合shiro的過濾器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter>
使用shiro提供的方式進行認證
/* * 使用者登入的方法-shiro提供的方式 */ public String login() { // 從session中獲取自動生成驗證碼 String key = (String) ServletActionContext.getRequest().getSession().getAttribute("key"); // 判斷輸入的驗證碼是否為空 if (StringUtils.isNotBlank(checkcode) && checkcode.equals(key)) { //獲得一個Subject物件 Subject subject = SecurityUtils.getSubject();//使用者認證狀態為“未認證” //使用者名稱密碼令牌 AuthenticationToken token =new UsernamePasswordToken(model.getUsername(), MD5Utils.md5(model.getPassword()));//密碼加密,和資料庫對應 try{ subject.login(token); //獲取簽名物件 User user = (User) subject.getPrincipal(); // 將物件寫回瀏覽器的session ServletActionContext.getRequest().getSession().setAttribute("loginUser", user); return HOME; }catch (UnknownAccountException e) {//shiro框架提供的異常,通過安全管理器捕獲,賬號不存在異常(原因是認證方法返回的是null) e.printStackTrace(); return LOGIN; }catch (IncorrectCredentialsException e) {//shiro框架提供的異常,通過安全管理器捕獲,密碼錯誤異常 e.printStackTrace(); return LOGIN; } } else { // 驗證碼錯誤,返回登入頁面 this.addActionError(this.getText("checkcodeerror")); return LOGIN; } }
自定義realm,實現認證和授權方法
/** * 自定義realm */ public class BosRealm extends AuthorizingRealm { // 注入dao @Autowired private IUserDao userDao; /** * 認證方法 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 獲取令牌(action傳過來的token),強轉成UsernamePasswordToken UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; // 得到頁面輸入的使用者名稱 String username = usernamePasswordToken.getUsername(); // 根據使用者名稱到資料庫中查詢密碼 User user = userDao.findUserByUsername(username); if (username == null) { return null; } String password = user.getPassword(); Object principal = user;// 簽名物件 Object credentials = password;// 資料庫中的密碼 String realmName = this.getName();// 當前realm的名稱 AuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName); return info; }
JdbcRealm加鹽,MD5加密(純數字的不安全)
實現加密方式:MD5(使用者名稱+密碼)或者MD5(MD5(使用者名稱+密碼))
第六步:在自定義Realm中實現授權方法
/** * 授權方法 */ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //簡單授權資訊物件 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("admin");//為當前使用者授權--admin許可權 info.addRole("admin");//為當前使用者授予admin角色 User user = (User) principals.getPrimaryPrincipal(); //TODO 後期需要連線資料庫,查詢當前登入人對應的實際的許可權 return info; }
shiro許可權控制註解方式
在applicationContext.xml中開啟shiro註解支援
<!-- 開啟shiro註解支援 --> <!-- 自動代理 --> <bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> <!--強制使用cglib建立action的代理, 不配置,spring預設是使用JDK代理, 預設情況下,action有介面就會使用JDK代理 --> <property name="proxyTargetClass" value="true"></property> </bean> <!-- 切面類 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"></bean>
在Action的方法上加入shiro提供的註解
/* * 批量作廢功能 */ @RequiresPermissions(value="delete")//執行這個方法,需要有delete這個許可權 public String deleteBatch() { userService.delete(id); return LIST; }
修改BaseAction的構造方法(判斷是JDK代理還是cglib代理)
ParameterizedType genericSuperclass =null; Type genericSuperclass2 = this.getClass().getGenericSuperclass(); if(genericSuperclass2 instanceof ParameterizedType){ //this為JDK建立的代理物件 genericSuperclass =(ParameterizedType) this.getClass().getGenericSuperclass(); }else{ //this為cglib建立的代理物件 genericSuperclass =(ParameterizedType) this.getClass().getSuperclass().getGenericSuperclass(); }
建立許可權模組資料模型(許可權表、角色表、使用者表、角色許可權關係表、使用者角色關係表)
使用者和許可權不直接建立關係,是為了方便後期授權