成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Shiro入門這篇就夠了【Shiro的基礎(chǔ)知識、回顧URL攔截】

chenjiang3 / 1244人閱讀

摘要:細(xì)粒度權(quán)限管理就是數(shù)據(jù)級別的權(quán)限管理。張三只能查看行政部的用戶信息,李四只能查看開發(fā)部門的用戶信息。比如通過的攔截器實(shí)現(xiàn)授權(quán)。

前言

本文主要講解的知識點(diǎn)有以下:

權(quán)限管理的基礎(chǔ)知識

模型

粗粒度和細(xì)粒度的概念

回顧URL攔截的實(shí)現(xiàn)

Shiro的介紹與簡單入門

一、Shiro基礎(chǔ)知識

在學(xué)習(xí)Shiro這個(gè)框架之前,首先我們要先了解Shiro需要的基礎(chǔ)知識:權(quán)限管理

1.1什么是權(quán)限管理?

只要有用戶參與的系統(tǒng)一般都要有權(quán)限管理,權(quán)限管理實(shí)現(xiàn)對用戶訪問系統(tǒng)的控制,按照安全規(guī)則或者安全策略控制用戶可以訪問而且只能訪問自己被授權(quán)的資源。

對權(quán)限的管理又分為兩大類別:

用戶認(rèn)證

用戶授權(quán)

1.1.1用戶認(rèn)證

用戶認(rèn)證,用戶去訪問系統(tǒng),系統(tǒng)要驗(yàn)證用戶身份的合法性

最常用的用戶身份驗(yàn)證的方法:1、用戶名密碼方式、2、指紋打卡機(jī)、3、基于證書驗(yàn)證方法。。系統(tǒng)驗(yàn)證用戶身份合法,用戶方可訪問系統(tǒng)的資源。

舉個(gè)例子:

當(dāng)我們輸入了自己的淘寶的賬戶和密碼,才能打開購物車

用戶認(rèn)證的流程:

判斷該資源能否不認(rèn)證就能訪問【登陸頁面、首頁】

如果該資源需要認(rèn)證后才能訪問,那么判斷該訪問者是否認(rèn)證了

如果還沒有認(rèn)證,那么需要返回到【登陸頁面】進(jìn)行認(rèn)證

認(rèn)證通過后才能訪問資源

從用戶認(rèn)證我們可以抽取出這么幾個(gè)概念

subject主體:理解為用戶,可能是程序,都要去訪問系統(tǒng)的資源,系統(tǒng)需要對subject進(jìn)行身份認(rèn)證

principal身份信息:通常是唯一的,一個(gè)主體還有多個(gè)身份信息,但是都有一個(gè)主身份信息(primary principal)【我們可以選擇身份證認(rèn)證、學(xué)生證認(rèn)證等等都是我們的身份信息】

credential憑證信息:可以是密碼 、證書、指紋。

總結(jié):主體在進(jìn)行身份認(rèn)證時(shí)需要提供身份信息和憑證信息。

1.1.2用戶授權(quán)

用戶授權(quán),簡單理解為訪問控制,在用戶認(rèn)證通過后,系統(tǒng)對用戶訪問資源進(jìn)行控制,用戶具有資源的訪問權(quán)限方可訪問。

用戶授權(quán)的流程

到達(dá)了用戶授權(quán)環(huán)節(jié),當(dāng)然是需要用戶認(rèn)證之后了

用戶訪問資源,系統(tǒng)判斷該用戶是否有權(quán)限去操作該資源

如果該用戶有權(quán)限才能夠訪問,如果沒有權(quán)限就不能訪問了

授權(quán)的過程可以簡單理解為:主體認(rèn)證之后,系統(tǒng)進(jìn)行訪問控制

subject必須具備資源的訪問權(quán)限才可訪問該資源..

權(quán)限/許可(permission) :針對資源的權(quán)限或許可,subject具有permission訪問資源,如何訪問/操作需要定義permission,權(quán)限比如:用戶添加、用戶修改、商品刪除

資源可以分為兩種

資源類型:系統(tǒng)的用戶信息就是資源類型,相當(dāng)于java類。

資源實(shí)例:系統(tǒng)中id為001的用戶就是資源實(shí)例,相當(dāng)于new的java對象。

1.2權(quán)限管理模型

一般地,我們可以抽取出這么幾個(gè)模型:

主體(賬號、密碼)

資源(資源名稱、訪問地址)

權(quán)限(權(quán)限名稱、資源id)

角色(角色名稱)

角色和權(quán)限關(guān)系(角色id、權(quán)限id)

主體和角色關(guān)系(主體id、角色id)

通常企業(yè)開發(fā)中將資源和權(quán)限表合并為一張權(quán)限表,如下:

資源(資源名稱、訪問地址)

權(quán)限(權(quán)限名稱、資源id)

合并為:

權(quán)限(權(quán)限名稱、資源名稱、資源訪問地址)

1.3分配權(quán)限

用戶需要分配相應(yīng)的權(quán)限才可訪問相應(yīng)的資源。權(quán)限是對于資源的操作許可。

通常給用戶分配資源權(quán)限需要將權(quán)限信息持久化,比如存儲在關(guān)系數(shù)據(jù)庫中。把用戶信息、權(quán)限管理、用戶分配的權(quán)限信息寫到數(shù)據(jù)庫(權(quán)限數(shù)據(jù)模型)

1.3.1基于角色訪問控制

RBAC(role based access control),基于角色的訪問控制。

//如果該user是部門經(jīng)理則可以訪問if中的代碼
if(user.hasRole("部門經(jīng)理")){
    //系統(tǒng)資源內(nèi)容
    //用戶報(bào)表查看
}

角色針對人劃分的,人作為用戶在系統(tǒng)中屬于活動(dòng)內(nèi)容,如果該 角色可以訪問的資源出現(xiàn)變更,需要修改你的代碼了

if(user.hasRole("部門經(jīng)理") || user.hasRole("總經(jīng)理")  ){
    //系統(tǒng)資源內(nèi)容
    //用戶報(bào)表查看
}

基于角色的訪問控制是不利于系統(tǒng)維護(hù)(可擴(kuò)展性不強(qiáng))。

1.3.2基于資源的訪問控制

RBAC(Resource based access control),基于資源的訪問控制。

資源在系統(tǒng)中是不變的,比如資源有:類中的方法,頁面中的按鈕。

對資源的訪問需要具有permission權(quán)限,代碼可以寫為:

if(user.hasPermission ("用戶報(bào)表查看(權(quán)限標(biāo)識符)")){
    //系統(tǒng)資源內(nèi)容
    //用戶報(bào)表查看
}

建議使用基于資源的訪問控制實(shí)現(xiàn)權(quán)限管理。

二、 粗粒度和細(xì)粒度權(quán)限

細(xì)粒度權(quán)限管理:對資源實(shí)例的權(quán)限管理。資源實(shí)例就資源類型的具體化,比如:用戶id為001的修改連接,1110班的用戶信息、行政部的員工。細(xì)粒度權(quán)限管理就是數(shù)據(jù)級別的權(quán)限管理。

粗粒度權(quán)限管理比如:超級管理員可以訪問戶添加頁面、用戶信息等全部頁面。部門管理員可以訪問用戶信息頁面包括 頁面中所有按鈕。

粗粒度和細(xì)粒度例子

系統(tǒng)有一個(gè)用戶列表查詢頁面,對用戶列表查詢分權(quán)限,

如果粗顆粒管理,張三和李四都有用戶列表查詢的權(quán)限,張三和李四都可以訪問用戶列表查詢。

進(jìn)一步進(jìn)行細(xì)顆粒管理,張三(行政部)和李四(開發(fā)部)只可以查詢自己本部門的用戶信息。

張三只能查看行政部 的用戶信息,李四只能查看開發(fā)部門的用戶信息。

細(xì)粒度權(quán)限管理就是數(shù)據(jù)級別的權(quán)限管理。
2.1如何實(shí)現(xiàn)粗粒度權(quán)限管理?

粗粒度權(quán)限管理比較容易將權(quán)限管理的代碼抽取出來在系統(tǒng)架構(gòu)級別統(tǒng)一處理。比如:通過springmvc的攔截器實(shí)現(xiàn)授權(quán)。

對細(xì)粒度權(quán)限管理在數(shù)據(jù)級別是沒有共性可言,針對細(xì)粒度權(quán)限管理就是系統(tǒng)業(yè)務(wù)邏輯的一部分,在業(yè)務(wù)層去處理相對比較簡單

比如:部門經(jīng)理只查詢本部門員工信息,在service接口提供一個(gè)部門id的參數(shù),controller中根據(jù)當(dāng)前用戶的信息得到該 用戶屬于哪個(gè)部門,調(diào)用service時(shí)將部門id傳入service,實(shí)現(xiàn)該用戶只查詢本部門的員工。

2.1.1基于URL攔截

基于url攔截的方式實(shí)現(xiàn)在實(shí)際開發(fā)中比較常用的一種方式。

對于web系統(tǒng),通過filter過慮器實(shí)現(xiàn)url攔截,也可以springmvc的攔截器實(shí)現(xiàn)基于url的攔截。

2.2.2使用權(quán)限管理框架實(shí)現(xiàn)

對于粗粒度權(quán)限管理,建議使用優(yōu)秀權(quán)限管理框架來實(shí)現(xiàn),節(jié)省開發(fā)成功,提高開發(fā)效率。

shiro就是一個(gè)優(yōu)秀權(quán)限管理框架。

三、回顧URL攔截

我們在學(xué)習(xí)的路途上也是使用過幾次URL對權(quán)限進(jìn)行攔截的

當(dāng)時(shí)我們做了權(quán)限的增刪該查的管理系統(tǒng),但是在權(quán)限表中是沒有把資源添加進(jìn)去,我們使用的是Map集合來進(jìn)行替代的。
http://blog.csdn.net/hon_3y/article/details/61926175

隨后,我們學(xué)習(xí)了動(dòng)態(tài)代理和注解,我們也做了一個(gè)基于注解的攔截

在Controller得到service對象的時(shí)候,service工廠返回的是一個(gè)動(dòng)態(tài)代理對象回去

Controller拿著代理對象去調(diào)用方法,代理對象就會去解析該方法上是否有注解

如果有注解,那么就需要我們進(jìn)行判斷該主體是否認(rèn)證了,如果認(rèn)證了就判斷該主體是否有權(quán)限

當(dāng)我們解析出該主體的權(quán)限和我們注解的權(quán)限是一致的時(shí)候,才放行!

http://blog.csdn.net/hon_3y/article/details/70767050

流程:

3.1認(rèn)證的JavaBean

我們之前認(rèn)證都是放在默認(rèn)的Javabean對象上的,現(xiàn)在既然我們準(zhǔn)備學(xué)Shiro了,我們就得專業(yè)一點(diǎn),弄一個(gè)專門存儲認(rèn)證信息的JavaBean


/**
 * 用戶身份信息,存入session 由于tomcat將session會序列化在本地硬盤上,所以使用Serializable接口
 * 
 * @author Thinkpad
 * 
 */
public class ActiveUser implements java.io.Serializable {
    private String userid;//用戶id(主鍵)
    private String usercode;// 用戶賬號
    private String username;// 用戶名稱

    private List menus;// 菜單
    private List permissions;// 權(quán)限

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


    public String getUsercode() {
        return usercode;
    }

    public void setUsercode(String usercode) {
        this.usercode = usercode;
    }

    public String getUserid() {
        return userid;
    }

    public void setUserid(String userid) {
        this.userid = userid;
    }

    public List getMenus() {
        return menus;
    }

    public void setMenus(List menus) {
        this.menus = menus;
    }

    public List getPermissions() {
        return permissions;
    }

    public void setPermissions(List permissions) {
        this.permissions = permissions;
    }

    
}

認(rèn)證的服務(wù)

    @Override
    public ActiveUser authenticat(String userCode, String password)
            throws Exception {
        /**
    認(rèn)證過程:
    根據(jù)用戶身份(賬號)查詢數(shù)據(jù)庫,如果查詢不到用戶不存在
    對輸入的密碼 和數(shù)據(jù)庫密碼 進(jìn)行比對,如果一致,認(rèn)證通過
         */
        //根據(jù)用戶賬號查詢數(shù)據(jù)庫
        SysUser sysUser = this.findSysUserByUserCode(userCode);
        
        if(sysUser == null){
            //拋出異常
            throw new CustomException("用戶賬號不存在");
        }
        
        //數(shù)據(jù)庫密碼 (md5密碼 )
        String password_db = sysUser.getPassword();
        
        //對輸入的密碼 和數(shù)據(jù)庫密碼 進(jìn)行比對,如果一致,認(rèn)證通過
        //對頁面輸入的密碼 進(jìn)行md5加密 
        String password_input_md5 = new MD5().getMD5ofStr(password);
        if(!password_input_md5.equalsIgnoreCase(password_db)){
            //拋出異常
            throw new CustomException("用戶名或密碼 錯(cuò)誤");
        }
        //得到用戶id
        String userid = sysUser.getId();
        //根據(jù)用戶id查詢菜單 
        List menus =this.findMenuListByUserId(userid);
        
        //根據(jù)用戶id查詢權(quán)限url
        List permissions = this.findPermissionListByUserId(userid);
        
        //認(rèn)證通過,返回用戶身份信息
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUserid(sysUser.getId());
        activeUser.setUsercode(userCode);
        activeUser.setUsername(sysUser.getUsername());//用戶名稱
        
        //放入權(quán)限范圍的菜單和url
        activeUser.setMenus(menus);
        activeUser.setPermissions(permissions);
        
        return activeUser;
    }

Controller處理認(rèn)證,如果身份認(rèn)證成功,那么把認(rèn)證信息存儲在Session中

    @RequestMapping("/login")
    public String login(HttpSession session, String randomcode,String usercode,String password)throws Exception{
        //校驗(yàn)驗(yàn)證碼,防止惡性攻擊
        //從session獲取正確驗(yàn)證碼
        String validateCode = (String) session.getAttribute("validateCode");
        
        //輸入的驗(yàn)證和session中的驗(yàn)證進(jìn)行對比 
        if(!randomcode.equals(validateCode)){
            //拋出異常
            throw new CustomException("驗(yàn)證碼輸入錯(cuò)誤");
        }
        
        //調(diào)用service校驗(yàn)用戶賬號和密碼的正確性
        ActiveUser activeUser = sysService.authenticat(usercode, password);
        
        //如果service校驗(yàn)通過,將用戶身份記錄到session
        session.setAttribute("activeUser", activeUser);
        //重定向到商品查詢頁面
        return "redirect:/first.action";
    }
    

身份認(rèn)證攔截器


    //在執(zhí)行handler之前來執(zhí)行的
    //用于用戶認(rèn)證校驗(yàn)、用戶權(quán)限校驗(yàn)
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //得到請求的url
        String url = request.getRequestURI();
        //判斷是否是公開 地址
        //實(shí)際開發(fā)中需要公開 地址配置在配置文件中
        //從配置中取逆名訪問url
        List open_urls = ResourcesUtil.gekeyList("anonymousURL");
        //遍歷公開 地址,如果是公開 地址則放行
        for(String open_url:open_urls){
            if(url.indexOf(open_url)>=0){
                //如果是公開 地址則放行
                return true;
            }
        }
        //判斷用戶身份在session中是否存在
        HttpSession session = request.getSession();
        ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
        //如果用戶身份在session中存在放行
        if(activeUser!=null){
            return true;
        }
        //執(zhí)行到這里攔截,跳轉(zhuǎn)到登陸頁面,用戶進(jìn)行身份認(rèn)證
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        
        //如果返回false表示攔截不繼續(xù)執(zhí)行handler,如果返回true表示放行
        return false;
    }

授權(quán)攔截器

    //在執(zhí)行handler之前來執(zhí)行的
    //用于用戶認(rèn)證校驗(yàn)、用戶權(quán)限校驗(yàn)
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //得到請求的url
        String url = request.getRequestURI();
        //判斷是否是公開 地址
        //實(shí)際開發(fā)中需要公開 地址配置在配置文件中
        //從配置中取逆名訪問url
        
        List open_urls = ResourcesUtil.gekeyList("anonymousURL");
        //遍歷公開 地址,如果是公開 地址則放行
        for(String open_url:open_urls){
            if(url.indexOf(open_url)>=0){
                //如果是公開 地址則放行
                return true;
            }
        }
        //從配置文件中獲取公共訪問地址
        List common_urls = ResourcesUtil.gekeyList("commonURL");
        //遍歷公用 地址,如果是公用 地址則放行
        for(String common_url:common_urls){
            if(url.indexOf(common_url)>=0){
                //如果是公開 地址則放行
                return true;
            }
        }
        //獲取session
        HttpSession session = request.getSession();
        ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
        //從session中取權(quán)限范圍的url
        List permissions = activeUser.getPermissions();
        for(SysPermission sysPermission:permissions){
            //權(quán)限的url
            String permission_url = sysPermission.getUrl();
            if(url.indexOf(permission_url)>=0){
                //如果是權(quán)限的url 地址則放行
                return true;
            }
        }
        
        //執(zhí)行到這里攔截,跳轉(zhuǎn)到無權(quán)訪問的提示頁面
        request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
        
        //如果返回false表示攔截不繼續(xù)執(zhí)行handler,如果返回true表示放行
        return false;
    }

攔截器配置:


    
    

        
            
            
            
        
        
            
            
            
        
    
四、什么是Shiro

shiro是apache的一個(gè)開源框架,是一個(gè)權(quán)限管理的框架,實(shí)現(xiàn) 用戶認(rèn)證、用戶授權(quán)

spring中有spring security (原名Acegi),是一個(gè)權(quán)限框架,它和spring依賴過于緊密,沒有shiro使用簡單。
shiro不依賴于spring,shiro不僅可以實(shí)現(xiàn) web應(yīng)用的權(quán)限管理,還可以實(shí)現(xiàn)c/s系統(tǒng),分布式系統(tǒng)權(quán)限管理,shiro屬于輕量框架,越來越多企業(yè)項(xiàng)目開始使用shiro。

Shiro架構(gòu):

subject:主體,可以是用戶也可以是程序,主體要訪問系統(tǒng),系統(tǒng)需要對主體進(jìn)行認(rèn)證、授權(quán)。

securityManager:安全管理器,主體進(jìn)行認(rèn)證和授權(quán)都 是通過securityManager進(jìn)行。

authenticator:認(rèn)證器,主體進(jìn)行認(rèn)證最終通過authenticator進(jìn)行的。

authorizer:授權(quán)器,主體進(jìn)行授權(quán)最終通過authorizer進(jìn)行的。

sessionManager:web應(yīng)用中一般是用web容器對session進(jìn)行管理,shiro也提供一套session管理的方式。

SessionDao: 通過SessionDao管理session數(shù)據(jù),針對個(gè)性化的session數(shù)據(jù)存儲需要使用sessionDao。

cache Manager:緩存管理器,主要對session和授權(quán)數(shù)據(jù)進(jìn)行緩存,比如將授權(quán)數(shù)據(jù)通過cacheManager進(jìn)行緩存管理,和ehcache整合對緩存數(shù)據(jù)進(jìn)行管理。

realm:域,領(lǐng)域,相當(dāng)于數(shù)據(jù)源,通過realm存取認(rèn)證、授權(quán)相關(guān)數(shù)據(jù)。

cryptography:密碼管理,提供了一套加密/解密的組件,方便開發(fā)。比如提供常用的散列、加/解密等功能。

比如md5散列算法。

五、為什么使用Shiro

我們在使用URL攔截的時(shí)候,要將所有的URL都配置起來,繁瑣、不易維護(hù)

而我們的Shiro實(shí)現(xiàn)系統(tǒng)的權(quán)限管理,有效提高開發(fā)效率,從而降低開發(fā)成本。

六、Shiro認(rèn)證 6.1導(dǎo)入jar包

我們使用的是Maven的坐標(biāo)就行了

    
            org.apache.shiro
            shiro-core
            1.2.3
        
        
            org.apache.shiro
            shiro-web
            1.2.3
        
        
            org.apache.shiro
            shiro-spring
            1.2.3
        
        
            org.apache.shiro
            shiro-ehcache
            1.2.3
        
        
            org.apache.shiro
            shiro-quartz
            1.2.3
        

當(dāng)然了,我們也可以把Shiro相關(guān)的jar包全部導(dǎo)入進(jìn)去


    org.apache.shiro
    shiro-all
    1.2.3


6.2Shiro認(rèn)證流程

6.2.1通過配置文件創(chuàng)建工廠

    // 用戶登陸和退出
    @Test
    public void testLoginAndLogout() {

        // 創(chuàng)建securityManager工廠,通過ini配置文件創(chuàng)建securityManager工廠
        Factory factory = new IniSecurityManagerFactory(
                "classpath:shiro-first.ini");

        // 創(chuàng)建SecurityManager
        SecurityManager securityManager = factory.getInstance();

        // 將securityManager設(shè)置當(dāng)前的運(yùn)行環(huán)境中
        SecurityUtils.setSecurityManager(securityManager);

        // 從SecurityUtils里邊創(chuàng)建一個(gè)subject
        Subject subject = SecurityUtils.getSubject();

        // 在認(rèn)證提交前準(zhǔn)備token(令牌)
        // 這里的賬號和密碼 將來是由用戶輸入進(jìn)去
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
                "111111");
        try {
            // 執(zhí)行認(rèn)證提交
            subject.login(token);
        } catch (AuthenticationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 是否認(rèn)證通過
        boolean isAuthenticated = subject.isAuthenticated();

        System.out.println("是否認(rèn)證通過:" + isAuthenticated);

        // 退出操作
        subject.logout();

        // 是否認(rèn)證通過
        isAuthenticated = subject.isAuthenticated();

        System.out.println("是否認(rèn)證通過:" + isAuthenticated);

    }

6.3小結(jié)

ModularRealmAuthenticator作用進(jìn)行認(rèn)證,需要調(diào)用realm查詢用戶信息(在數(shù)據(jù)庫中存在用戶信息)
ModularRealmAuthenticator進(jìn)行密碼對比(認(rèn)證過程)。
realm:需要根據(jù)token中的身份信息去查詢數(shù)據(jù)庫(入門程序使用ini配置文件),如果查到用戶返回認(rèn)證信息,如果查詢不到返回null。

6.4自定義realm

從第一個(gè)認(rèn)證程序我們可以看見,我們所說的流程,是認(rèn)證器去找realm去查詢我們相對應(yīng)的數(shù)據(jù)。而默認(rèn)的realm是直接去與配置文件來比對的,一般地,我們在開發(fā)中都是讓realm去數(shù)據(jù)庫中比對。
因此,我們需要自定義realm

public class CustomRealm extends AuthorizingRealm {

    // 設(shè)置realm的名稱
    @Override
    public void setName(String name) {
        super.setName("customRealm");
    }

    // 用于認(rèn)證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        // token是用戶輸入的
        // 第一步從token中取出身份信息
        String userCode = (String) token.getPrincipal();

        // 第二步:根據(jù)用戶輸入的userCode從數(shù)據(jù)庫查詢
        // ....
    

        // 如果查詢不到返回null
        //數(shù)據(jù)庫中用戶賬號是zhangsansan
        /*if(!userCode.equals("zhangsansan")){//
            return null;
        }*/
        
        
        // 模擬從數(shù)據(jù)庫查詢到密碼
        String password = "111112";

        // 如果查詢到返回認(rèn)證信息AuthenticationInfo

        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                userCode, password, this.getName());

        return simpleAuthenticationInfo;
    }

    // 用于授權(quán)
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }

}
6.5配置realm

需要在shiro-realm.ini配置realm注入到securityManager中。

6.6測試自定義realm

同上邊的入門程序,需要更改ini配置文件路徑:

同上邊的入門程序,需要更改ini配置文件路徑:
Factory factory = new IniSecurityManagerFactory(
                "classpath:shiro-realm.ini");
6.7散列算法

我們?nèi)绻續(xù)d5,我們就會知道m(xù)d5是不可逆的,但是如果設(shè)置了一些安全性比較低的密碼:111111...即時(shí)是不可逆的,但還是可以通過暴力算法來得到md5對應(yīng)的明文...

建議對md5進(jìn)行散列時(shí)加salt(鹽),進(jìn)行加密相當(dāng) 于對原始密碼+鹽進(jìn)行散列。

正常使用時(shí)散列方法:

在程序中對原始密碼+鹽進(jìn)行散列,將散列值存儲到數(shù)據(jù)庫中,并且還要將鹽也要存儲在數(shù)據(jù)庫中。

測試:

public class MD5Test {
    
    public static void main(String[] args) {
        
        //原始 密碼 
        String source = "111111";
        //鹽
        String salt = "qwerty";
        //散列次數(shù)
        int hashIterations = 2;
        //上邊散列1次:f3694f162729b7d0254c6e40260bf15c
        //上邊散列2次:36f2dfa24d0a9fa97276abbe13e596fc
        
        
        //構(gòu)造方法中:
        //第一個(gè)參數(shù):明文,原始密碼 
        //第二個(gè)參數(shù):鹽,通過使用隨機(jī)數(shù)
        //第三個(gè)參數(shù):散列的次數(shù),比如散列兩次,相當(dāng) 于md5(md5(""))
        Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);
        
        String password_md5 =  md5Hash.toString();
        System.out.println(password_md5);
        //第一個(gè)參數(shù):散列算法 
        SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
        System.out.println(simpleHash.toString());
    }

}
6.8自定義realm支持md5

自定義realm

public class CustomRealmMd5 extends AuthorizingRealm {

    // 設(shè)置realm的名稱
    @Override
    public void setName(String name) {
        super.setName("customRealmMd5");
    }

    // 用于認(rèn)證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        // token是用戶輸入的
        // 第一步從token中取出身份信息
        String userCode = (String) token.getPrincipal();

        // 第二步:根據(jù)用戶輸入的userCode從數(shù)據(jù)庫查詢
        // ....

        // 如果查詢不到返回null
        // 數(shù)據(jù)庫中用戶賬號是zhangsansan
        /*
         * if(!userCode.equals("zhangsansan")){// return null; }
         */

        // 模擬從數(shù)據(jù)庫查詢到密碼,散列值
        String password = "f3694f162729b7d0254c6e40260bf15c";
        // 從數(shù)據(jù)庫獲取salt
        String salt = "qwerty";
        //上邊散列值和鹽對應(yīng)的明文:111111

        // 如果查詢到返回認(rèn)證信息AuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                userCode, password, ByteSource.Util.bytes(salt), this.getName());

        return simpleAuthenticationInfo;
    }

    // 用于授權(quán)
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }

}

配置文件:

測試:

// 自定義realm實(shí)現(xiàn)散列值匹配
    @Test
    public void testCustomRealmMd5() {

        // 創(chuàng)建securityManager工廠,通過ini配置文件創(chuàng)建securityManager工廠
        Factory factory = new IniSecurityManagerFactory(
                "classpath:shiro-realm-md5.ini");

        // 創(chuàng)建SecurityManager
        SecurityManager securityManager = factory.getInstance();

        // 將securityManager設(shè)置當(dāng)前的運(yùn)行環(huán)境中
        SecurityUtils.setSecurityManager(securityManager);

        // 從SecurityUtils里邊創(chuàng)建一個(gè)subject
        Subject subject = SecurityUtils.getSubject();

        // 在認(rèn)證提交前準(zhǔn)備token(令牌)
        // 這里的賬號和密碼 將來是由用戶輸入進(jìn)去
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
                "222222");

        try {
            // 執(zhí)行認(rèn)證提交
            subject.login(token);
        } catch (AuthenticationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 是否認(rèn)證通過
        boolean isAuthenticated = subject.isAuthenticated();

        System.out.println("是否認(rèn)證通過:" + isAuthenticated);

    }
七、總結(jié)

用戶認(rèn)證和用戶授權(quán)是Shiro的基礎(chǔ),用戶認(rèn)證其實(shí)上就是登陸操作、用戶授權(quán)實(shí)際上就是對資源攔截的操作。

權(quán)限管理的模型一般我們都將資源放在權(quán)限表中進(jìn)行管理起來。

我們可以基于角色攔截,也可以基于資源攔截。要是基于角色攔截的話,那么如果角色的權(quán)限發(fā)生變化了,那就需要修改代碼了。推薦使用基于資源進(jìn)行攔截

這次URL攔截,我們使用一個(gè)JavaBean來封裝所有的認(rèn)證信息。當(dāng)用戶登陸了之后,我們就把用戶對菜單欄的訪問、對資源的訪問權(quán)限都封裝到該JavaBean中

當(dāng)使用攔截器進(jìn)行用戶認(rèn)證的時(shí)候,我們只要判斷Session域有沒有JavaBen對象即可了。

當(dāng)時(shí)候攔截器進(jìn)行用戶授權(quán)的時(shí)候,我們要判斷JavaBean中的權(quán)限是否能夠訪問該資源。

以前URL攔截的方式需要把所有的URL都在數(shù)據(jù)庫進(jìn)行管理。非常麻煩,不易維護(hù)。

我們希望Shiro去認(rèn)證的時(shí)候是通過realm去數(shù)據(jù)庫查詢數(shù)據(jù)的。而我們r(jià)eaml默認(rèn)是查詢配置文件的數(shù)據(jù)的。

因此,我們需要自定義reaml,使得它是去數(shù)據(jù)庫查詢數(shù)據(jù)。只要繼承AuthorizingRealm類就行了。

當(dāng)然了,自定義后的reaml也需要在配置文件中寫上我們的自定義reaml的位置的。

散列算法就是為了讓密碼不被別人給破解。我們可對原始的密碼加鹽再進(jìn)行散列,這就加大了破解的難度了。

自定義的reaml也是支持散列算法的,相同的,還是需要我們在配置文件中配置一下就好了。

如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號:Java3y

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68858.html

相關(guān)文章

  • Java3y文章目錄導(dǎo)航

    摘要:前言由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個(gè)博客導(dǎo)航。 前言 由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個(gè)博客導(dǎo)航。 由于更新比較頻繁,因此隔一段時(shí)間才會更新目錄導(dǎo)航哦~想要獲取最新原創(chuàng)的技術(shù)文章歡迎關(guān)注我的公眾號:Java3y Java3y文章目錄導(dǎo)航 Java基礎(chǔ) 泛型就這么簡單 注解就這么簡單 Druid數(shù)據(jù)庫連接池...

    KevinYan 評論0 收藏0
  • shiro入門筆記

    摘要:當(dāng)前可以是身份,不需要經(jīng)過認(rèn)證或者在原先的中存在記錄。當(dāng)前必須擁有所有指定的角色時(shí),才能訪問被該注解標(biāo)注的方法。 關(guān)于 Apache Shiro 概念基本都粘自官網(wǎng) http://shiro.apache.org/詳細(xì)中文博客 http://wiki.jikexueyuan.com/p...與SpringBoot整合 https://segmentfault.com/a/11... ...

    yagami 評論0 收藏0
  • Spring Security

    摘要:框架具有輕便,開源的優(yōu)點(diǎn),所以本譯見構(gòu)建用戶管理微服務(wù)五使用令牌和來實(shí)現(xiàn)身份驗(yàn)證往期譯見系列文章在賬號分享中持續(xù)連載,敬請查看在往期譯見系列的文章中,我們已經(jīng)建立了業(yè)務(wù)邏輯數(shù)據(jù)訪問層和前端控制器但是忽略了對身份進(jìn)行驗(yàn)證。 重拾后端之Spring Boot(四):使用JWT和Spring Security保護(hù)REST API 重拾后端之Spring Boot(一):REST API的搭建...

    keelii 評論0 收藏0
  • Shiro【授權(quán)、整合Spirng、Shiro過濾器】

    摘要:表示對用戶資源進(jìn)行操作,相當(dāng)于,對所有用戶資源實(shí)例進(jìn)行操作。與整合,實(shí)際上的操作都是通過過濾器來干的。將安全管理器交由工廠來進(jìn)行管理。在過濾器鏈中設(shè)置靜態(tài)資源不攔截。 前言 本文主要講解的知識點(diǎn)有以下: Shiro授權(quán)的方式簡單介紹 與Spring整合 初始Shiro過濾器 一、Shiro授權(quán) 上一篇我們已經(jīng)講解了Shiro的認(rèn)證相關(guān)的知識了,現(xiàn)在我們來弄Shiro的授權(quán) Shir...

    ralap 評論0 收藏0
  • JS正則表達(dá)式入門,看這篇夠了

    摘要:如果遇到非常的復(fù)雜的匹配,正則表達(dá)式的優(yōu)勢就更加明顯了。關(guān)于正則表達(dá)式書寫規(guī)則,可查看,上面說的很清楚了,我就不貼出來了。替換與正則表達(dá)式匹配的子串,并返回替換后的字符串。結(jié)語正則表達(dá)式并不難,懂了其中的套路之后,一切都變得簡單了。 前言 在正文開始前,先說說正則表達(dá)式是什么,為什么要用正則表達(dá)式?正則表達(dá)式在我個(gè)人看來就是一個(gè)瀏覽器可以識別的規(guī)則,有了這個(gè)規(guī)則,瀏覽器就可以幫我們判斷...

    wenzi 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<