1. 程式人生 > >shiro許可權筆記

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

匿名過濾器

org.apache.shiro.web.filter.authc.AnonymousFilter

authc

認證後過濾器

org.apache.shiro.web.filter.authc.FormAuthenticationFilter

perms

許可權過濾器

org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

port

 

org.apache.shiro.web.filter.authz.PortFilter

rest

 

org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

noSessionCreation

 

org.apache.shiro.web.filter.session.NoSessionCreationFilter

authcBasic

 

org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

roles

角色過濾器

org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

ssl

安全協議過濾器

org.apache.shiro.web.filter.authz.SslFilter

user

使用者過濾器

org.apache.shiro.web.filter.authc.UserFilter

logout

退出過濾器

org.apache.shiro.web.filter.authc.LogoutFilter

 

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();
        }     

 建立許可權模組資料模型(許可權表、角色表、使用者表、角色許可權關係表、使用者角色關係表)

使用者和許可權不直接建立關係,是為了方便後期授權