Shiro權限認證與授權筆記

一  將Shirojar包導入web項目

二 在web.xml中配置shiro代理過濾器

注意: 該過濾器需要配置在struts2過濾器之前

  <!-- 配置Shiro的代理過濾器 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

三 在spring的配置文件applicationContext.xml中配置Shiro的過濾器

注意:過濾器ShiroFilterFactoryBean的id必須與web.xm中的過濾器name屬性值一致

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
       <!-- 注入shiro的安全管理員 -->
       <property name="securityManager" ref="securityManager"></property>
       <!--

    注入登錄路徑

    loginUrl :沒有登錄的用戶請求需要登錄的頁面時自動跳轉到登錄頁面,不是必須的屬性,

    不輸入地址的話會自動尋找項目web項目的根目錄下的”/login.jsp”頁面。

   -->
       <property name="loginUrl" value="/login.jsp"></property>
       <!--

    注入登錄成功的路徑

    successUrl :登錄成功默認跳轉頁面,不配置則跳轉至”/”。如果登陸前點擊的一個需要登錄的頁面,

    則在登錄自動跳轉到那個需要登錄的頁面。不跳轉到此。

   -->
       <property name="successUrl" value="/index.jsp"></property>
       <!--

    注入權限不足的路徑

    unauthorizedUrl :沒有權限默認跳轉的頁面。

   -->
       <property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"></property>
       <!-- url權限級別的控制 -->
       <property name="FilterChainDefinitions">
           <value>

        

    <!-- 對頁面應用的css文件放行 anon表示不需要任何權限就能訪問 -->
               /css/** = anon

    <!-- 對頁面應用的js文件放行 -->
               /js/** = anon

    <!-- 對頁面應用的圖片images文件放行 -->
               /images/** = anon

    <!-- 對頁面應用的驗證碼jsp文件,jsp後面加*號是在驗證碼jsp後面跟參數也放行 -->
               /validatecode.jsp* = anon

    <!-- 對頁面應用的登錄頁面放行 -->
               /login.jsp* = anon

    <!-- 對頁面應用的登錄提交的login.action類放行 -->
               /user_login* = anon

    <!-- 對訪問staff.action設置權限限制 -->
               /page_base_staff.action = perms[staff]

    <!-- 對其他上面沒有設置的路徑設置權限設置 -->

    <!--  過濾器鏈的執行順序是自上而下依次匹配, 如果能匹配上, 則不再往下匹配  -->
               /** = authc
           </value>
       </property>
    </bean>

四 在登錄方法中,編寫Shiro相關的代碼

//登錄功能
    public String login () {
        HttpServletRequest request = ServletActionContext.getRequest();
        //1.驗證碼校驗
        String validateCode = (String) request.getSession().getAttribute("key");
        if (StringUtils.containsWhitespace(checkcode) || !validateCode.equalsIgnoreCase(checkcode)) {
            //1.1如果校驗不成功,跳轉到登錄頁面,並提示"驗證碼不正確的信息"
            this.addActionError(this.getText("checkCodeError"));
            return "login";
        }
        //2.如果校驗成功實現登錄功能
        //創建subject權限對象

   //Subject 是與程序進行交互的對象,可以是人也可以是服務或者其他,通常就理解爲用戶。
   //所有Subject 實例都必須綁定到一個SecurityManager上。我們與一個 Subject 交互,

   //運行時shiro會自動轉化爲與 SecurityManager交互的特定 subject的交互。
 

        Subject subject = SecurityUtils.getSubject();
        //創建用戶名和密碼的令牌
        String username = model.getUsername();
        String password = model.getPassword();
        password = MD5Utils.md5(password);
        AuthenticationToken token = new UsernamePasswordToken(username, password);
        //調用安全管理器
        try {
            subject.login(token);
            //從subject中獲取保存在安全管理員中的user對象
            User user = (User) subject.getPrincipal();

     //將用戶保存在session中,因爲自定義攔截器的原因(如果沒有自定義攔截器, 將用戶存放在session域中的這個步驟可以省略)
            request.getSession().setAttribute("loginUser", user);
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            this.addActionError(this.getText("usernameError"));
            return "login";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            this.addActionError(this.getText("passwordError"));
            return "login";
        }
        return "home";
    }

 五 創建Realm安全數據橋, 通過繼承AuthorizingRealm的方式實現

 public class BOSRealm extends AuthorizingRealm {
    @Resource
    private IUserDao userDao;

    //權限認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken)
            throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) paramAuthenticationToken;
        String username = token.getUsername();

   //調用userdao根據用戶名查詢用戶
        User user = userDao.findByUsername(username);
        if (user != null) {
            //如果查詢的用戶存在
            //TODO 與數據庫中用戶名和密碼進行比對。比對成功則返回info,比對失敗則拋出對應信息的異常AuthenticationException
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,
                    user.getPassword(), this.getClass().getName());
            return authenticationInfo;
        } else {

    //如果查詢不到用戶, 返回空, Shiro會拋出UnknownAccountException異常
            return null;
        }
    }
    
    //授予權限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
        // TODO Auto-generated method stub
        return null;
    }

}

 六  在Spring配置文件applicationContext.xml中配置Shiro安全管理器

<!-- 7配置Shiro的安全管理器 -->
    <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
       <!-- 注入realm數據橋 -->
       <property name="realm" ref="bosRealm"></property>
    </bean>

<!--  配置Realm數據橋對象  -->
    <bean id="bosRealm" class="cn.rodge.bos.shiro.BOSRealm"></bean>

七  在自定義Realm中, 爲當前用戶授權

在Shiro權限認證之後, 認證過的用戶對於特定權限的頁面或者功能仍然不具備訪問權限, 此時就需要針對不同的用戶進行相應的授權操作. Shiro的授權操作是在權限認證的基礎之上完成的. 需要修改BOSRealm類中的權限授予的方法.

//授予權限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
        //創建授權信息對象
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //根據當前用戶查詢數據庫,獲取其權限對象
        //獲取當前用戶,由於shiro的過濾器在struts的過濾器之前執行,因此此時的用戶還沒有被封裝到session中,
        //故獲取當前用戶在session中娶不到
        /*Subject subject = SecurityUtils.getSubject();
        User loginUser = (User) subject.getPrincipal();*/
        User loginUser = (User) paramPrincipalCollection.getPrimaryPrincipal();
        if (loginUser != null) {
            List<Function> list = null;
            //表示用戶存在,調用roledao根據用戶查詢所有權限
            if ("admin".equals(loginUser.getUsername())) {
                //如果是超級管理員,賦予所有權限
                list = functionDao.findAll();
            } else {
                //根據用戶id查詢所有權限
                list = functionDao.findFunctionByUserId(loginUser.getId());
            }
            if (list != null && list.size() > 0) {
                for (Function function : list) {

       //爲用戶授權
                    simpleAuthorizationInfo.addStringPermission(function.getCode());
                }
            }
            return simpleAuthorizationInfo;
        } else {
            return null;
        }
    }

七  查詢用戶權限的dao層方法

  @SuppressWarnings("unchecked")
    @Override
    //根據用戶id查詢權限
    public List<Function> findFunctionByUserId(String id) {
        String hql = "from Function f left outer join fetch f.roles r "
                + "left outer join fetch r.users u where u.id = ?";
        return this.getHibernateTemplate().find(hql, id);
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章