shiro安全框架的入門


shiro認證方式

1. 認證:現在使用咱們的系統的認證方式就是指通過用戶名和密碼登錄該系統,然后可以使用該系統提供的模塊功能。
    * 在生活中其實有很多的認證手動,例如指紋識別,人臉識別、短信驗證等。
    * 使用shiro框架的認證,指的是登錄功能!!

2. 咱們系統中采用的就是用戶名和密碼的驗證的方式
    * 傳統的驗證方式:客戶端發送請求 --> Action接收請求參數(調用service和dao) --> 封裝到HttpSession對象 --> 轉發到成功JSP頁面 --> 響應給客戶端
    * 咱們項目中使用的是Shiro的驗證方式

3. Shiro的安全框架
    * Shiro是一個安全框架,是Apache開源組織提供的,用於解決系統的認證和授權的問題,同時也提供了會話管理和數據加密等功能。
    * Shiro的驗證方式
        * 客戶端 --> Action接收請求參數 --> Action調用Shiro的安全框架
            * 調用service,通過用戶名查詢出該用戶,再根據客戶的傳遞密碼和數據庫密碼進行比較,需要單獨編寫密碼比較器,如果密碼比較成功后通過認證,授權 
        * 登錄成功存入到HttpSession --> 轉發到成功頁面 --> 響應給客戶端

shiro框架的概述

1. 查看提供的文檔
    * Apache Shiro是Java的一個安全框架。功能強大,使用簡單的Java安全框架
    * 它為開發人員提供一個直觀而全面的認證,授權,加密及會話管理的解決方案

2.Shiro核心的功能
    * Authentication:身份認證/登錄,驗證用戶是不是擁有相應的身份
    * Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限
    * Session Manager:會話管理,即用戶登錄后就是一次會話,在沒有退出之前,它的所有信息都在會話中
    * Cryptography:加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲

3. 從應用程序角度來觀看Shiro框架

shiro認證的入門

1. 因為現在沒有提供Realm域,所以先自己手動提供配置文件
    * 創建shiro.ini的配置文件,寫入如下代碼
        [users]
        meimei=1234

2. 編寫入門程序
    @Test
    public void demo1(){
        // 通過工廠,加載配置文件
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        // 通過工廠獲取到安全管理器
        SecurityManager securityManager = factory.getInstance();
        // 獲取到subject對象,但是需要先注冊工具
        SecurityUtils.setSecurityManager(securityManager);
        // 獲取到subject對象
        Subject subject = SecurityUtils.getSubject();
        // 就可以認證了
        AuthenticationToken token = new UsernamePasswordToken("meimei", "12345");
        // 這就是認證
        subject.login(token);
        System.out.println("認證通過...");
    }

spring整合shiro安全框架————

框架的使用

1. 導入jar包,如果使用了Maven,引入坐標即可(項目配置文件中已經引入)
2. 配置Spring整合Shiro的核心過濾器,核心filter,一個filter相當於10個filter
    * 注意:shiro的filter必須在struts2的filter之前,否則action無法創建
    * 代碼如下
        <!-- Shiro Security filter  filter-name這個名字的值將來還會在spring中用到  -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

4. Spring整合Shiro框架,需要配置
    * 創建applicationContext-shiro.xml的配置文件,引入約束
        * 在applicationContext配置文件引入<import resource="classpath:spring/applicationContext-shiro.xml"></import>

    * 配置安全管理器
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <!-- 必須要注入自定義Realm域,至少提供一個 -->
            <property name="realm" ref="authRealm"/>
        </bean>

    * 配置自定義Realm域,准備提供數據
        <!-- 配置自定義Realm域 -->
        <bean id="authRealm" class="cn.itcast.jk.shiro.AuthRealm">
            <!-- 注入密碼比較器  -->
            <property name="credentialsMatcher" ref="passwordMatcher"/>
        </bean>

        * 注意:該Realm域還沒有創建,需要自己手動創建,Realm類必須要繼承AuthorizingRealm類,這是編寫Realm域的規范。就相當於過濾器要實現Filter接口一個道理。
        * 有2個抽象方法必須添加實現,具體的代碼如下
            /**
             * 自定義Realm域
             * @author Administrator
             */
            public class AuthRealm extends AuthorizingRealm{

                @Resource(name="userService")
                private UserService userService;

                /**
                 * 授權
                 */
                protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
                    return null;
                }

                /**
                 * 認證
                 */
                protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
                    return null;
                }
            }

    * 配置密碼比較器的類,密碼比較器的類也需要自己手動創建,需要繼承SimpleCredentialsMatcher類,重寫doCredentialsMatch方法進行密碼比較
        * 具體的代碼如下
            /**
             * 密碼比較器
             * @author Administrator
             */
            public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{
                /**
                 * 用於進行密碼比較的
                 */
                public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

                    return super.doCredentialsMatch(token, info);
                }
            }

        * 配置如下
            <bean id="passwordMatcher" class="cn.itcast.jk.shiro.CustomCredentialsMatcher"/>

    * 配置生成過濾器Bean對象的工廠
        <!-- filter-name這個名字的值來自於web.xml中filter的名字 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <!--登錄頁面  -->
            <property name="loginUrl" value="/index.jsp"></property>
            <!-- 登錄成功后,暫時沒用到 -->      
            <property name="successUrl" value="/home.action"></property>
            <property name="filterChainDefinitions">
                <!-- /**代表下面的多級目錄也過濾 -->
                <value>
                    /index.jsp* = anon
                    /home* = anon
                    /sysadmin/login/login.jsp* = anon
                    /sysadmin/login/loginAction_logout* = anon
                    /login* = anon
                    /logout* = anon
                    /components/** = anon
                    /css/** = anon
                    /img/** = anon
                    /js/** = anon
                    /plugins/** = anon
                    /images/** = anon
                    /js/** = anon
                    /make/** = anon
                    /skin/** = anon
                    /stat/** = anon
                    /ufiles/** = anon
                    /validator/** = anon
                    /resource/** = anon
                    /** = authc   
                    /*.* = authc
                </value>
            </property>
        </bean>

5. 測試
    * 首先修改LoginAction類的login的方法,添加如下代碼
        // 判斷用戶名是否為空,如果為空,跳轉到登錄頁面
        if(UtilFuns.isEmpty(username)){
            return LOGIN;
        }

Md5hash加密算法

1. 導入工具類Encrypt類

登錄認證的代碼編寫

1. 打開AuthRealm類,准備完成認證代碼的編寫。認證就是登錄功能,最疼密碼需要一致,先編寫密碼比較器
2. 打開CustomCredentialsMatcher類,准備編寫代碼
    /**
     * 密碼比較器
     * @author Administrator
     */
    public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{

        /**
         * 用於進行密碼比較的
         * token -- 表示從頁面傳過來的用戶名和密碼
         * info  -- 表示從數據庫中查詢到的密碼
         */
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            // 把token向下強轉成實現類
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
            // 獲取密碼
            String inputPwd = new String(upToken.getPassword());
            // 對密碼加密
            String md5Pwd = Encrypt.md5(inputPwd, upToken.getUsername());
            // 獲取到數據庫中的密碼
            String dbPwd = info.getCredentials().toString();
            return super.equals(md5Pwd, dbPwd);
        }
    }

3. 打開AuthRealm類,完成認證的方法編寫,具體的代碼如下
    /**
     * 認證
     * AuthenticationToken token 表示頁面傳過來的用戶名和密碼
     * 邏輯:通過用戶名查詢數據庫,獲取到該用戶的密碼,封裝到AuthenticationInfo對象中,返回。
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        // 獲取到用戶名
        String username = upToken.getUsername();
        // 通過用戶名查詢數據
        List<User> list = userService.find("from User where userName = ?", User.class,new Object[]{username});
        if(list != null && list.size() > 0){
            User user = list.get(0);
            // 獲取到該用戶,構造方法,第二個參數表示密碼,第三個參數隨便定義字符串的名稱
            AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
            return info;
        }
        return null;
    }

編寫登錄的方法

1. 搭建LoginAction,編寫login的登錄方法,具體代碼如下
    public String login() throws Exception {
        // 判斷
        if(UtilFuns.isEmpty(username)){
            return LOGIN;
        }
        try {
            // 先獲取到Subject對象
            Subject subject = SecurityUtils.getSubject();
            // 創建UsernamePasswordToken對象,封裝用戶名和密碼
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            // 使用shiro框架進行校驗
            subject.login(token);
            // 獲取返回的結果
            User user = (User) subject.getPrincipal();
            // 存入到session中
            ServletActionContext.getRequest().getSession().setAttribute(SysConstant.CURRENT_USER_INFO, user);
            return SUCCESS;
        } catch (Exception e) {
            e.printStackTrace();
            super.put("errorInfo", "用戶名或者密碼錯誤!!");
            return "login";
        }
    }

編寫退出的方法

1. 具體的代碼如下
    //退出
    public String logout(){
        //刪除session
        session.remove(SysConstant.CURRENT_USER_INFO);      
        SecurityUtils.getSubject().logout();
        return "logout";
    }

用戶授權的代碼編寫

1. 授權功能:認證通過后的用戶,所擁有的權限。
2. shiro框架提供和權限有關的標簽庫
    * <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
    * <shiro:hasPermission name="系統首頁">,判斷認證通過后的用戶,是否擁有系統首頁的權限?如果該用戶擁有系統首頁權限,把標簽中間的內容顯示到頁面上。

3. 打開home文件夾下的title.jsp,把動態獲取菜單代碼打開
4. 打開AuthRealm類,完成授權的方法編寫,具體的代碼如下
    /**
     * 授權
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        // 從AuthenticationInfo中獲取到用戶對象
        User user = (User) pc.fromRealm(this.getName()).iterator().next();
        List<String> list = new ArrayList<String>();
        // 繼續操作,通過對象導航的方式,獲取到該用戶下的角色,具有哪些權限
        Set<Role> roles = user.getRoles();
        // 遍歷,獲取到每一個角色對象
        for (Role role : roles) {
            // 通過角色對象獲取到該角色具有的權限
            Set<Module> modules = role.getModules();
            for (Module module : modules) {
                list.add(module.getName());
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(list);
        return info;
    }

5. 問題
    * 如果訪問系統管理下部門Action中的所有的方法,必須有部門管理的權限
        * /sysadmin/deptAction_* = perms["部門管理"]

6. 也可以使用注解的方式進行權限校驗
    * 先添加注解的配置
        <!-- 保證實現了Shiro內部lifecycle函數的bean執行 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

        <!-- 生成代理,通過代理進行控制 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
              depends-on="lifecycleBeanPostProcessor">
            <property name="proxyTargetClass" value="true"/>
        </bean>

        <!-- 安全管理器 -->
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager"/>
        </bean>

    * 在Action的方法添加注解
        @RequiresPermissions(value="部門管理")

 




 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM