shiro安全框架的入門

shiro認證方式css

1. 認證:如今使用我們的系統的認證方式就是指經過用戶名和密碼登陸該系統,而後能夠使用該系統提供的模塊功能。
    * 在生活中其實有不少的認證手動,例如指紋識別,人臉識別、短信驗證等。
    * 使用shiro框架的認證,指的是登陸功能!!

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

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

shiro框架的概述web

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安全框架————

框架的使用spring

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類

登陸認證的代碼編寫apache

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";
        }
    }

編寫退出的方法session

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

用戶受權的代碼編寫app

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="部門管理")
相關文章
相關標籤/搜索