大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 Shiro攔截器機(jī)制

Shiro攔截器機(jī)制

更新時間:2021-11-16 10:34:09 來源:動力節(jié)點(diǎn) 瀏覽1386次

攔截器介紹

Shiro 使用了與 Servlet 一樣的 Filter 接口進(jìn)行擴(kuò)展

1.NameableFilter

NameableFilter 給 Filter 起個名字,如果沒有設(shè)置默認(rèn)就是 FilterName;還記得之前的如 authc 嗎?當(dāng)我們組裝攔截器鏈時會根據(jù)這個名字找到相應(yīng)的攔截器實(shí)例;

2.OncePerRequestFilter

OncePerRequestFilter 用于防止多次執(zhí)行 Filter 的;也就是說一次請求只會走一次攔截器鏈;另外提供 enabled 屬性,表示是否開啟該攔截器實(shí)例,默認(rèn) enabled=true 表示開啟,如果不想讓某個攔截器工作,可以設(shè)置為 false 即可。

3.ShiroFilter

ShiroFilter 是整個 Shiro 的入口點(diǎn),用于攔截需要安全控制的請求進(jìn)行處理,這個之前已經(jīng)用過了。

4.AdviceFilter

AdviceFilter 提供了 AOP 風(fēng)格的支持,類似于 SpringMVC 中的 Interceptor:

boolean preHandle(ServletRequest request, ServletResponse response) throws Exception
void postHandle(ServletRequest request, ServletResponse response) throws Exception
void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception; 

preHandler:類似于 AOP 中的前置增強(qiáng);在攔截器鏈執(zhí)行之前執(zhí)行;如果返回 true 則繼續(xù)攔截器鏈;否則中斷后續(xù)的攔截器鏈的執(zhí)行直接返回;進(jìn)行預(yù)處理(如基于表單的身份驗證、授權(quán))

postHandle:類似于 AOP 中的后置返回增強(qiáng);在攔截器鏈執(zhí)行完成后執(zhí)行;進(jìn)行后處理(如記錄執(zhí)行時間之類的);

afterCompletion:類似于 AOP 中的后置最終增強(qiáng);即不管有沒有異常都會執(zhí)行;可以進(jìn)行清理資源(如接觸 Subject 與線程的綁定之類的);

5.PathMatchingFilter

PathMatchingFilter 提供了基于 Ant 風(fēng)格的請求路徑匹配功能及攔截器參數(shù)解析的功能,如“roles[admin,user]”自動根據(jù)“,”分割解析到一個路徑參數(shù)配置并綁定到相應(yīng)的路徑:

boolean pathsMatch(String path, ServletRequest request)
boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception 

pathsMatch:該方法用于 path 與請求路徑進(jìn)行匹配的方法;如果匹配返回 true;

onPreHandle:在 preHandle 中,當(dāng) pathsMatch 匹配一個路徑后,會調(diào)用 opPreHandler 方法并將路徑綁定參數(shù)配置傳給 mappedValue;然后可以在這個方法中進(jìn)行一些驗證(如角色授權(quán)),如果驗證失敗可以返回 false 中斷流程;默認(rèn)返回 true;也就是說子類可以只實(shí)現(xiàn) onPreHandle 即可,無須實(shí)現(xiàn) preHandle。如果沒有 path 與請求路徑匹配,默認(rèn)是通過的(即 preHandle 返回 true)。

6.AccessControlFilter

AccessControlFilter 提供了訪問控制的基礎(chǔ)功能;比如是否允許訪問/當(dāng)訪問拒絕時如何處理等:

abstract boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;
boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;
abstract boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception; 

isAccessAllowed:表示是否允許訪問;mappedValue 就是[urls]配置中攔截器參數(shù)部分,如果允許訪問返回 true,否則 false;

onAccessDenied:表示當(dāng)訪問拒絕時是否已經(jīng)處理了;如果返回 true 表示需要繼續(xù)處理;如果返回 false 表示該攔截器實(shí)例已經(jīng)處理了,將直接返回即可。

onPreHandle 會自動調(diào)用這兩個方法決定是否繼續(xù)處理:

boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
    return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
} 

另外 AccessControlFilter 還提供了如下方法用于處理如登錄成功后/重定向到上一個請求:

void setLoginUrl(String loginUrl) //身份驗證時使用,默認(rèn)/login.jsp
String getLoginUrl()
Subject getSubject(ServletRequest request, ServletResponse response) //獲取Subject 實(shí)例
boolean isLoginRequest(ServletRequest request, ServletResponse response)//當(dāng)前請求是否是登錄請求
void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException //將當(dāng)前請求保存起來并重定向到登錄頁面
void saveRequest(ServletRequest request) //將請求保存起來,如登錄成功后再重定向回該請求
void redirectToLogin(ServletRequest request, ServletResponse response) //重定向到登錄頁面 

比如基于表單的身份驗證就需要使用這些功能。

到此基本的攔截器就完事了,如果我們想進(jìn)行訪問訪問的控制就可以繼承 AccessControlFilter;如果我們要添加一些通用數(shù)據(jù)我們可以直接繼承 PathMatchingFilter。

攔截器鏈

Shiro 對 Servlet 容器的 FilterChain 進(jìn)行了代理,即 ShiroFilter 在繼續(xù) Servlet 容器的 Filter 鏈的執(zhí)行之前,通過 ProxiedFilterChain 對 Servlet 容器的 FilterChain 進(jìn)行了代理;即先走 Shiro 自己的 Filter 體系,然后才會委托給 Servlet 容器的 FilterChain 進(jìn)行 Servlet 容器級別的 Filter 鏈執(zhí)行;Shiro 的 ProxiedFilterChain 執(zhí)行流程:1、先執(zhí)行 Shiro 自己的 Filter 鏈;2、再執(zhí)行 Servlet 容器的 Filter 鏈(即原始的 Filter)。

而 ProxiedFilterChain 是通過 FilterChainResolver 根據(jù)配置文件中[urls]部分是否與請求的 URL 是否匹配解析得到的。

FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);

即傳入原始的 chain 得到一個代理的 chain。

Shiro 內(nèi)部提供了一個路徑匹配的 FilterChainResolver 實(shí)現(xiàn):PathMatchingFilterChainResolver,其根據(jù)[urls]中配置的 url 模式(默認(rèn) Ant 風(fēng)格)=攔截器鏈和請求的 url 是否匹配來解析得到配置的攔截器鏈的;而 PathMatchingFilterChainResolver 內(nèi)部通過 FilterChainManager 維護(hù)著攔截器鏈,比如 DefaultFilterChainManager 實(shí)現(xiàn)維護(hù)著 url 模式與攔截器鏈的關(guān)系。因此我們可以通過 FilterChainManager 進(jìn)行動態(tài)動態(tài)增加 url 模式與攔截器鏈的關(guān)系。

DefaultFilterChainManager 會默認(rèn)添加 org.apache.shiro.web.filter.mgt.DefaultFilter 中聲明的攔截器:

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
} 

如果要注冊自定義攔截器,IniSecurityManagerFactory/WebIniSecurityManagerFactory 在啟動時會自動掃描 ini 配置文件中的 [filters]/[main] 部分并注冊這些攔截器到 DefaultFilterChainManager;且創(chuàng)建相應(yīng)的 url 模式與其攔截器關(guān)系鏈。如果使用 Spring 后續(xù)章節(jié)會介紹如果注冊自定義攔截器。

如果想自定義 FilterChainResolver,可以通過實(shí)現(xiàn) WebEnvironment 接口完成:

public class MyIniWebEnvironment extends IniWebEnvironment {
    @Override
    protected FilterChainResolver createFilterChainResolver() {
        //在此處擴(kuò)展自己的FilterChainResolver
        return super.createFilterChainResolver();
    }
} 

FilterChain 之間的關(guān)系。如果想動態(tài)實(shí)現(xiàn) url -攔截器的注冊,就可以通過實(shí)現(xiàn)此處的 FilterChainResolver 來完成,比如:

//1、創(chuàng)建 FilterChainResolver
PathMatchingFilterChainResolver filterChainResolver =
        new PathMatchingFilterChainResolver();
//2、創(chuàng)建 FilterChainManager
DefaultFilterChainManager filterChainManager = new DefaultFilterChainManager();
//3、注冊 Filter
for(DefaultFilter filter : DefaultFilter.values()) {
    filterChainManager.addFilter(
        filter.name(), (Filter) ClassUtils.newInstance(filter.getFilterClass()));
}
//4、注冊 URL-Filter 的映射關(guān)系
filterChainManager.addToChain("/login.jsp", "authc");
filterChainManager.addToChain("/unauthorized.jsp", "anon");
filterChainManager.addToChain("/**", "authc");
filterChainManager.addToChain("/**", "roles", "admin");
//5、設(shè)置 Filter 的屬性
FormAuthenticationFilter authcFilter =
         (FormAuthenticationFilter)filterChainManager.getFilter("authc");
authcFilter.setLoginUrl("/login.jsp");
RolesAuthorizationFilter rolesFilter =
          (RolesAuthorizationFilter)filterChainManager.getFilter("roles");
rolesFilter.setUnauthorizedUrl("/unauthorized.jsp");
filterChainResolver.setFilterChainManager(filterChainManager);
return filterChainResolver; 

此處自己去實(shí)現(xiàn)注冊 filter,及url 模式與 filter 之間的映射關(guān)系??梢酝ㄟ^定制 FilterChainResolver 或 FilterChainManager 來完成諸如動態(tài) URL 匹配的實(shí)現(xiàn)。

然后再 web.xml 中進(jìn)行如下配置 Environment:

<context-param>
<param-name>shiroEnvironmentClass</param-name> <param-value>com.github.zhangkaitao.shiro.chapter8.web.env.MyIniWebEnvironment</param-value>
</context-param>&nbsp;

自定義攔截器

通過自定義自己的攔截器可以擴(kuò)展一些功能,諸如動態(tài) url -角色/權(quán)限訪問控制的實(shí)現(xiàn)、根據(jù) Subject 身份信息獲取用戶信息綁定到 Request(即設(shè)置通用數(shù)據(jù))、驗證碼驗證、在線用戶信息的保存等等,因為其本質(zhì)就是一個 Filter;所以 Filter 能做的它就能做。

1.擴(kuò)展 OncePerRequestFilter

OncePerRequestFilter 保證一次請求只調(diào)用一次 doFilterInternal,即如內(nèi)部的 forward 不會再多執(zhí)行一次 doFilterInternal:

public class MyOncePerRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        System.out.println("=========once per request filter");
        chain.doFilter(request, response);
    }
}&nbsp;

然后再 shiro.ini 配置文件中:

[main]
myFilter1=com.github.zhangkaitao.shiro.chapter8.web.filter.MyOncePerRequestFilter
\#[filters]
\#myFilter1=com.github.zhangkaitao.shiro.chapter8.web.filter.MyOncePerRequestFilter
[urls]
/**=myFilter1&nbsp;

2.擴(kuò)展 AdviceFilter

AdviceFilter 提供了 AOP 的功能,其實(shí)現(xiàn)和 SpringMVC 中的 Interceptor 思想一樣:

public class MyAdviceFilter extends AdviceFilter {
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("====預(yù)處理/前置處理");
        return true;//返回 false 將中斷后續(xù)攔截器鏈的執(zhí)行
    }
    @Override
    protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("====后處理/后置返回處理");
    }
    @Override
    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
        System.out.println("====完成處理/后置最終處理");
    }
}&nbsp;

preHandle:進(jìn)行請求的預(yù)處理,然后根據(jù)返回值決定是否繼續(xù)處理(true:繼續(xù)過濾器鏈);可以通過它實(shí)現(xiàn)權(quán)限控制;

postHandle:執(zhí)行完攔截器鏈之后正常返回后執(zhí)行;

afterCompletion:不管最后有沒有異常,afterCompletion 都會執(zhí)行,完成如清理資源功能。

然后在 shiro.ini 中進(jìn)行如下配置:

[filters]
myFilter1=com.github.zhangkaitao.shiro.chapter8.web.filter.MyOncePerRequestFilter
myFilter2=com.github.zhangkaitao.shiro.chapter8.web.filter.MyAdviceFilter
[urls]
/**=myFilter1,myFilter2&nbsp;

該過濾器的具體使用可參考我的 SpringMVC 教程中的處理器攔截器部分。

3.PathMatchingFilter

PathMatchingFilter 繼承了 AdviceFilter,提供了 url 模式過濾的功能,如果需要對指定的請求進(jìn)行處理,可以擴(kuò)展 PathMatchingFilter:

public class MyPathMatchingFilter extends PathMatchingFilter {
    @Override
    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
       System.out.println("url matches,config is " + Arrays.toString((String[])mappedValue));
       return true;
    }
}&nbsp;

preHandle:會進(jìn)行 url 模式與請求 url 進(jìn)行匹配,如果匹配會調(diào)用 onPreHandle;如果沒有配置 url 模式 / 沒有 url 模式匹配,默認(rèn)直接返回 true;

onPreHandle:如果 url 模式與請求 url 匹配,那么會執(zhí)行 onPreHandle,并把該攔截器配置的參數(shù)傳入。默認(rèn)什么不處理直接返回 true。

然后在 shiro.ini 中進(jìn)行如下配置:

[filters]
myFilter3=com.github.zhangkaitao.shiro.chapter8.web.filter.MyPathMatchingFilter
[urls]
/**= myFilter3[config]&nbsp;

/** 就是注冊給 PathMatchingFilter 的 url 模式,config 就是攔截器的配置參數(shù),多個之間逗號分隔,onPreHandle 使用 mappedValue 接收參數(shù)值。

4.擴(kuò)展 AccessControlFilter

AccessControlFilter 繼承了 PathMatchingFilter,并擴(kuò)展了了兩個方法:

public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
    return isAccessAllowed(request, response, mappedValue)
     || onAccessDenied(request, response, mappedValue);
}&nbsp;

isAccessAllowed:即是否允許訪問,返回 true 表示允許;

onAccessDenied:表示訪問拒絕時是否自己處理,如果返回 true 表示自己不處理且繼續(xù)攔截器鏈執(zhí)行,返回 false 表示自己已經(jīng)處理了(比如重定向到另一個頁面)。

public class MyAccessControlFilter extends AccessControlFilter {
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        System.out.println("access allowed");
        return true;
    }
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("訪問拒絕也不自己處理,繼續(xù)攔截器鏈的執(zhí)行");
        return true;
    }
}&nbsp;

然后在 shiro.ini 中進(jìn)行如下配置:

5.基于表單登錄攔截器

之前我們已經(jīng)使用過 Shiro 內(nèi)置的基于表單登錄的攔截器了,此處自己做一個類似的基于表單登錄的攔截器。

public class FormLoginFilter extends PathMatchingFilter {
    private String loginUrl = "/login.jsp";
    private String successUrl = "/";
    @Override
    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        if(SecurityUtils.getSubject().isAuthenticated()) {
            return true;//已經(jīng)登錄過
        }
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if(isLoginRequest(req)) {
            if("post".equalsIgnoreCase(req.getMethod())) {//form表單提交
                boolean loginSuccess = login(req); //登錄
                if(loginSuccess) {
                    return redirectToSuccessUrl(req, resp);
                }
            }
            return true;//繼續(xù)過濾器鏈
        } else {//保存當(dāng)前地址并重定向到登錄界面
            saveRequestAndRedirectToLogin(req, resp);
            return false;
        }
    }
    private boolean redirectToSuccessUrl(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        WebUtils.redirectToSavedRequest(req, resp, successUrl);
        return false;
    }
    private void saveRequestAndRedirectToLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        WebUtils.saveRequest(req);
        WebUtils.issueRedirect(req, resp, loginUrl);
    }
    private boolean login(HttpServletRequest req) {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        try {
            SecurityUtils.getSubject().login(new UsernamePasswordToken(username, password));
        } catch (Exception e) {
            req.setAttribute("shiroLoginFailure", e.getClass());
            return false;
        }
        return true;
    }
    private boolean isLoginRequest(HttpServletRequest req) {
        return pathsMatch(loginUrl, WebUtils.getPathWithinApplication(req));
    }
}&nbsp;

onPreHandle 主要流程:

首先判斷是否已經(jīng)登錄過了,如果已經(jīng)登錄過了繼續(xù)攔截器鏈即可;

如果沒有登錄,看看是否是登錄請求,如果是 get 方法的登錄頁面請求,則繼續(xù)攔截器鏈(到請求頁面),否則如果是 get 方法的其他頁面請求則保存當(dāng)前請求并重定向到登錄頁面;

如果是 post 方法的登錄頁面表單提交請求,則收集用戶名 / 密碼登錄即可,如果失敗了保存錯誤消息到 “shiroLoginFailure” 并返回到登錄頁面;

如果登錄成功了,且之前有保存的請求,則重定向到之前的這個請求,否則到默認(rèn)的成功頁面。

shiro.ini 配置

[filters]
formLogin=com.github.zhangkaitao.shiro.chapter8.web.filter.FormLoginFilter
[urls]
/test.jsp=formLogin
/login.jsp=formLogin&nbsp;

6.任意角色授權(quán)攔截器

Shiro 提供 roles 攔截器,其驗證用戶擁有所有角色,沒有提供驗證用戶擁有任意角色的攔截器。

public class AnyRolesFilter extends AccessControlFilter {
    private String unauthorizedUrl = "/unauthorized.jsp";
    private String loginUrl = "/login.jsp";
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        String[] roles = (String[])mappedValue;
        if(roles == null) {
            return true;//如果沒有設(shè)置角色參數(shù),默認(rèn)成功
        }
        for(String role : roles) {
            if(getSubject(request, response).hasRole(role)) {
                return true;
            }
        }
        return false;//跳到onAccessDenied處理
    }
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        if (subject.getPrincipal() == null) {//表示沒有登錄,重定向到登錄頁面
            saveRequest(request);
            WebUtils.issueRedirect(request, response, loginUrl);
        } else {
            if (StringUtils.hasText(unauthorizedUrl)) {//如果有未授權(quán)頁面跳轉(zhuǎn)過去
                WebUtils.issueRedirect(request, response, unauthorizedUrl);
            } else {//否則返回401未授權(quán)狀態(tài)碼
                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
            }
        }
        return false;
    }
} 

流程:

首先判斷用戶有沒有任意角色,如果沒有返回 false,將到 onAccessDenied 進(jìn)行處理;

如果用戶沒有角色,接著判斷用戶有沒有登錄,如果沒有登錄先重定向到登錄;

如果用戶沒有角色且設(shè)置了未授權(quán)頁面(unauthorizedUrl),那么重定向到未授權(quán)頁面;否則直接返回 401 未授權(quán)錯誤碼。

shiro.ini 配置

[filters]
anyRoles=com.github.zhangkaitao.shiro.chapter8.web.filter.AnyRolesFilter
[urls]
/test.jsp=formLogin,anyRoles[admin,user]
/login.jsp=formLogin&nbsp;

此處可以繼承 AuthorizationFilter 實(shí)現(xiàn),其提供了授權(quán)相關(guān)的基礎(chǔ)代碼。如果大家想了解更多相關(guān)知識,可以關(guān)注一下動力節(jié)點(diǎn)的Shiro視頻教程,里面的課程內(nèi)容豐富,適合小白學(xué)習(xí),希望對大家能夠有所幫助。

提交申請后,顧問老師會電話與您溝通安排學(xué)習(xí)

免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 香蕉视频黄色片 | 欧美狠狠入鲁的视频极速 | 国产亚洲精品久久久久久午夜 | 日日摸夜夜摸狠狠摸日日碰夜夜做 | 一级毛片私人影院 | 综合啪啪 | 亚洲成人www| 欧美日韩国产58香蕉在线视频 | 国产精品麻豆高清在线观看 | 一级女人18片毛片免费视频 | 色综久久天天综合绕视看 | 在线操 | 欧美激情观看一区二区久久 | 2019国产精品视频 | 九一毛片 | 久久久久久免费精品视频 | 奇米狠狠| 国产中文字幕在线免费观看 | 俄罗斯老妇性欧美毛茸茸孕交 | 噜鲁射图片 | se在线播放 | 久久香蕉国产精品一区二区三 | 欧美专区在线 | 亚洲va欧美va国产综合久久 | 国产精品深夜福利免费观看 | 99在线视频网站 | 精品91在线 | 国产伦精品一区二区免费 | 国产精品亚欧美一区二区三区 | 久久国产精品久久国产片 | 欧美洲久久日韩欧美 | 岛国毛片一级一级特级毛片 | 国产精品青青青高清在线密亚 | 国产精品18久久久久久久久久 | 国产成人精品综合久久久 | 99久久中文字幕伊人情人 | 八戒久久精品一区二区三区 | 国产女人体一区二区三区 | 欧美日韩中字 | 天天干天天色天天干 | 最新狠狠色狠狠色综合 |