乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      理解這9大內(nèi)置過(guò)濾器,才算是精通Shiro

       鷹兔牛熊眼 2020-05-13

      小Hub領(lǐng)讀:

      權(quán)限框架一般都是一堆過(guò)濾器、攔截器的組合運(yùn)用,在shiro中,有多少個(gè)內(nèi)置的過(guò)濾器你知道嗎?在哪些場(chǎng)景用那些過(guò)濾器,這篇文章希望你能對(duì)shiro有個(gè)新的認(rèn)識(shí)!

      別忘了,點(diǎn)個(gè) [在看] 支持一下哈~


      前兩篇原創(chuàng)shiro相關(guān)文章:

      1、極簡(jiǎn)入門,Shiro的認(rèn)證與授權(quán)流程解析

      2、只需要6個(gè)步驟,springboot集成shiro,并完成登錄


      我們都知道shiro是個(gè)認(rèn)證權(quán)限框架,除了登錄、退出邏輯我們需要侵入項(xiàng)目代碼之外,驗(yàn)證用戶是否已經(jīng)登錄、是否擁有權(quán)限的代碼其實(shí)都是過(guò)濾器來(lái)完成的,可以這么說(shuō),shiro其實(shí)就是一個(gè)過(guò)濾器鏈集合。

      那么今天我們?cè)敿?xì)討論一下shiro底層到底給我們提供了多少默認(rèn)的過(guò)濾器供我們使用,又都有什么用呢?帶著問(wèn)題,我們先去shiro官網(wǎng)看看對(duì)于默認(rèn)過(guò)濾器集的說(shuō)明。

      • http://shiro./web.html#default-filters

      When running a web-app, Shiro will create some useful default Filter instances and make them available in the [main] section automatically. You can configure them in main as you would any other bean and reference them in your chain definitions.

      The default Filter instances available automatically are defined by the DefaultFilter enum and the enum’s name field is the name available for configuration.

      翻譯過(guò)來(lái)意思:

      當(dāng)運(yùn)行web應(yīng)用程序時(shí),Shiro將創(chuàng)建一些有用的默認(rèn)過(guò)濾器實(shí)例,并使它們?cè)赱main]部分自動(dòng)可用。您可以像配置任何其他bean一樣在main中配置它們,并在鏈定義中引用它們。

      默認(rèn)篩選器實(shí)例由DefaultFilter enum中定義,enum s name字段是可用于配置的名稱。

      于是我看了一下 DefaultFilter的源碼:

      1. public enum DefaultFilter {

      2. anon(AnonymousFilter.class),

      3. authc(FormAuthenticationFilter.class),

      4. authcBasic(BasicHttpAuthenticationFilter.class),

      5. logout(LogoutFilter.class),

      6. noSessionCreation(NoSessionCreationFilter.class),

      7. perms(PermissionsAuthorizationFilter.class),

      8. port(PortFilter.class),

      9. rest(HttpMethodPermissionFilter.class),

      10. roles(RolesAuthorizationFilter.class),

      11. ssl(SslFilter.class),

      12. user(UserFilter.class);

      13. ...

      14. }

      終于知道我們常用的anon、authc、perms、roles、user過(guò)濾器是哪里來(lái)的了!這些過(guò)濾器我們都是可以直接使用的。但你要弄清楚這些默認(rèn)過(guò)濾器,你還不得不去深入了解一下shiro更底層為我們提供的過(guò)濾器,基本我們的這些默認(rèn)過(guò)濾器都是通過(guò)繼承這幾個(gè)底層過(guò)濾器演變而來(lái)的。

      那么這些過(guò)濾器都有哪些呢?我們來(lái)看一個(gè)圖:

      上面我標(biāo)記了7個(gè)我們接下來(lái)要介紹的過(guò)濾器,我們一個(gè)個(gè)來(lái)介紹,弄清楚這些過(guò)濾器之后,相信你對(duì)shiro的認(rèn)識(shí)會(huì)更深一層了。具體authc、perms、roles等這些默認(rèn)過(guò)濾器與這7個(gè)過(guò)濾器有什么關(guān)系你就會(huì)明白。

      1、AbstractFilter

      這個(gè)過(guò)濾器還得說(shuō)說(shuō),shiro最底層的抽象過(guò)濾器,雖然我們極少直接繼承它,它通過(guò)實(shí)現(xiàn) Filter獲得過(guò)濾器的特性。

      完成一些過(guò)濾器基本初始化操作, FilterConfig:過(guò)濾器配置對(duì)象,用于servlet容器在初始化期間將信息傳遞給其他過(guò)濾器。

      2、NameableFilter

      命名過(guò)濾器,給過(guò)濾器定義名稱!也是比較基層的過(guò)濾器了,未拓展其他功能,我們很少會(huì)直接繼承這個(gè)過(guò)濾器。為重寫doFilter方法。

      3、OncePerRequestFilter

      重寫doFilter方法,保證每個(gè)servlet方法只會(huì)被過(guò)濾一次。可以看到doFilter方法中,第一行代碼就是 StringalreadyFilteredAttributeName=getAlreadyFilteredAttributeName();然后通過(guò) request.getAttribute(alreadyFilteredAttributeName)!=null來(lái)判斷過(guò)濾器是否已經(jīng)被調(diào)用過(guò),從而保證過(guò)濾器不會(huì)被重復(fù)調(diào)用。

      進(jìn)入方法之前,先標(biāo)記 alreadyFilteredAttributeName為True,抽象 doFilterInternal方法執(zhí)行之后再remove掉 alreadyFilteredAttributeName。

      所以O(shè)ncePerRequestFilter過(guò)濾器保證只會(huì)被一次調(diào)用的功能,提供了抽象方法 doFilterInternal讓后面的過(guò)濾器可以重寫,執(zhí)行真正的過(guò)濾器處理邏輯。

      1. protected abstract void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)

      2. throws ServletException, IOException;

      這個(gè)過(guò)濾器我們已經(jīng)可以開(kāi)始在我們的項(xiàng)目繼承使用,比如攔截用戶請(qǐng)求,判斷用戶是否已經(jīng)登錄(攜帶token或cookie信息),如果未登錄則返回Json數(shù)據(jù)告知未登錄!

      比如:開(kāi)源mblog博客項(xiàng)目中,過(guò)濾器就是繼承OncePerRequestFilter。

      • https:///mtons/mblog

      1. /**

      2. * 公眾號(hào):MarkerHub

      3. **/

      4. public class AuthenticatedFilter extends OncePerRequestFilter {

      5. // 前端彈窗的js代碼

      6. private static final String JS = '<script type='text/javascript'>var wp=window.parent; if(wp!=null){while(wp.parent&&wp.parent!==wp){wp=wp.parent;}wp.location.href='%1$s';}else{window.location.href='%1$s';}</script>';

      7. private String loginUrl = '/login';

      8. // 重寫doFilterInternal方法

      9. @Override

      10. protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)

      11. throws ServletException, IOException {

      12. Subject subject = SecurityUtils.getSubject();

      13. // 已經(jīng)登陸就跳過(guò)過(guò)濾器

      14. if (subject.isAuthenticated() || subject.isRemembered()) {

      15. chain.doFilter(request, response);

      16. } else {

      17. // 未登錄就返回json或者js代碼

      18. WebUtils.saveRequest(request);

      19. String path = WebUtils.getContextPath((HttpServletRequest) request);

      20. String url = loginUrl;

      21. if (StringUtils.isNotBlank(path) && path.length() > 1) {

      22. url = path + url;

      23. }

      24. if (isAjaxRequest((HttpServletRequest) request)) {

      25. response.setContentType('application/json;charset=UTF-8');

      26. response.getWriter().print(JSON.toJSONString(Result.failure('您還沒(méi)有登錄!')));

      27. } else {

      28. response.getWriter().write(new Formatter().format(JS, url).toString());

      29. }

      30. }

      31. }

      32. }

      未登錄情況,ajax請(qǐng)求過(guò)濾器返回 您還沒(méi)有登錄!提示,web請(qǐng)求則返回一段js代碼,前端渲染會(huì)跳出一個(gè)登陸窗口,這也就是未什么大家常遇到的點(diǎn)擊登錄,當(dāng)前跳出一個(gè)登陸彈窗的一種實(shí)現(xiàn)方式!

      效果:

      4、AdviceFilter

      看到Advice,很自然想到切面環(huán)繞編程,一般有pre、post、after幾個(gè)方法。所以這個(gè)AdviceFilter過(guò)濾器就是提供了和AOP相似的切面功能。

      繼承OncePerRequestFilter過(guò)濾器重寫doFilterInternal方法,我們可以先看看:

      可以看到上面4個(gè)序號(hào):

      • 1、preHandle 前置過(guò)濾,默認(rèn)true

      • 2、executeChain 執(zhí)行真正代碼過(guò)濾邏輯->chain.doFilter

      • 3、postHandle 后置過(guò)濾

      • 4、cleanup 其實(shí)主要邏輯是afterCompletion方法

      于是,我們從OncePerRequestFilter的一個(gè)doFilterInternal分化成了切面編程,更容易前后控制執(zhí)行邏輯。所以如果繼承AdviceFilter時(shí)候,我們可以重寫preHandle方法,判斷用戶是否滿足已登錄或者其他業(yè)務(wù)邏輯,返回false時(shí)候表示不通過(guò)過(guò)濾器。

      5、PathMatchingFilter

      請(qǐng)求路徑匹配過(guò)濾器,通過(guò)匹配請(qǐng)求url,判斷請(qǐng)求是否需要過(guò)濾,如果url未在需要過(guò)濾的集合內(nèi),則跳過(guò),否則進(jìn)入 isFilterChainContinued的onPreHandle方法。

      我們可以看下代碼:

      從上面3個(gè)步驟中可以看到,PathMatchingFilter提供的功能是:自定義匹配url,匹配上的請(qǐng)求最終跳轉(zhuǎn)到 onPreHandle方法。

      這個(gè)過(guò)濾器為后面的常用過(guò)濾器提供的基礎(chǔ),比如我們?cè)赾onfig中配置如下

      1. /login = anon

      2. /admin/* = authc

      攔截/login請(qǐng)求,經(jīng)過(guò)AnonymousFilter過(guò)濾器,我們可以看下

      • org.apache.shiro.web.filter.authc.AnonymousFilter

      1. public class AnonymousFilter extends PathMatchingFilter {

      2. /**

      3. * 公眾號(hào):MarkerHub

      4. **/

      5. @Override

      6. protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) {

      7. // Always return true since we allow access to anyone

      8. return true;

      9. }

      10. }

      AnonymousFilter重寫了onPreHandle方法,只不過(guò)直接返回了true,說(shuō)明攔截的鏈接可以直接通過(guò),不需要其他攔截邏輯。

      而authc->FormAuthenticationFilter也是間接繼承了PathMatchingFilter。

      1. public class FormAuthenticationFilter extends AuthenticatingFilter

      所以,需要攔截某個(gè)鏈接進(jìn)行業(yè)務(wù)邏輯過(guò)濾的可以繼承PathMatchingFilter方法拓展哈。

      6、AccessControlFilter

      訪問(wèn)控制過(guò)濾器。繼承PathMatchingFilter過(guò)濾器,重寫onPreHandle方法,又分出了兩個(gè)抽象方法來(lái)控制

      • isAccessAllowed 是否允許訪問(wèn)

      • onAccessDenied 是否拒絕訪問(wèn)

      所以,我們現(xiàn)在可以通過(guò)重寫這個(gè)抽象兩個(gè)方法來(lái)控制過(guò)濾邏輯。另外多提供了3個(gè)方法,方便后面的過(guò)濾器使用。

      1. /**

      2. * 公眾號(hào):MarkerHub

      3. **/

      4. protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {

      5. saveRequest(request);

      6. redirectToLogin(request, response);

      7. }

      8. protected void saveRequest(ServletRequest request) {

      9. WebUtils.saveRequest(request);

      10. }

      11. protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {

      12. String loginUrl = getLoginUrl();

      13. WebUtils.issueRedirect(request, response, loginUrl);

      14. }

      其中redirectToLogin提供了調(diào)整到登錄頁(yè)面的邏輯與實(shí)現(xiàn),為后面的過(guò)濾器發(fā)現(xiàn)未登錄跳轉(zhuǎn)到登錄頁(yè)面提供了基礎(chǔ)。

      這個(gè)過(guò)濾器,我們可以靈活運(yùn)用。

      7、AuthenticationFilter

      繼承AccessControlFilter,重寫了isAccessAllowed方法,通過(guò)判斷用戶是否已經(jīng)完成登錄來(lái)判斷用戶是否允許繼續(xù)后面的邏輯判斷。這里可以看出,從這個(gè)過(guò)濾器開(kāi)始,后續(xù)的判斷會(huì)與用戶的登錄狀態(tài)相關(guān),直接繼承這些過(guò)濾器,我們不需要再自己手動(dòng)去判斷用戶是否已經(jīng)登錄。并且提供了登錄成功之后跳轉(zhuǎn)的方法。

      1. public abstract class AuthenticationFilter extends AccessControlFilter {

      2. public void setSuccessUrl(String successUrl) {

      3. this.successUrl = successUrl;

      4. }

      5. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

      6. Subject subject = getSubject(request, response);

      7. return subject.isAuthenticated();

      8. }

      9. }

      8、AuthenticatingFilter

      繼承AuthenticationFilter,提供了自動(dòng)登錄、是否登錄請(qǐng)求等方法。

      1. /**

      2. * 公眾號(hào):MarkerHub

      3. **/

      4. public abstract class AuthenticatingFilter extends AuthenticationFilter {

      5. public static final String PERMISSIVE = 'permissive';

      6. //TODO - complete JavaDoc

      7. protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {

      8. AuthenticationToken token = createToken(request, response);

      9. if (token == null) {

      10. String msg = 'createToken method implementation returned null. A valid non-null AuthenticationToken ' +

      11. 'must be created in order to execute a login attempt.';

      12. throw new IllegalStateException(msg);

      13. }

      14. try {

      15. Subject subject = getSubject(request, response);

      16. subject.login(token);

      17. return onLoginSuccess(token, subject, request, response);

      18. } catch (AuthenticationException e) {

      19. return onLoginFailure(token, e, request, response);

      20. }

      21. }

      22. protected abstract AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception;

      23. /**

      24. * 公眾號(hào):MarkerHub

      25. **/

      26. @Override

      27. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

      28. return super.isAccessAllowed(request, response, mappedValue) ||

      29. (!isLoginRequest(request, response) && isPermissive(mappedValue));

      30. }

      31. ...

      32. }

      • executeLogin 執(zhí)行登錄

      • onLoginSuccess 登錄成功跳轉(zhuǎn)

      • onLoginFailure 登錄失敗跳轉(zhuǎn)

      • createToken 創(chuàng)建登錄的身份token

      • isAccessAllowed 是否允許被訪問(wèn)

      • isLoginRequest 是否登錄請(qǐng)求

      這個(gè)方法提供了自動(dòng)登錄的課程,比如我們獲取到token之后實(shí)行自動(dòng)登錄,這場(chǎng)景還是很場(chǎng)景的。

      比如在開(kāi)源項(xiàng)目renren-fast中,就是這樣處理的:

      • https:///renrenio/renren-fast

      1. public class OAuth2Filter extends AuthenticatingFilter {

      2. @Override

      3. protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {

      4. //獲取請(qǐng)求token

      5. String token = getRequestToken((HttpServletRequest) request);

      6. if(StringUtils.isBlank(token)){

      7. return null;

      8. }

      9. return new OAuth2Token(token);

      10. }

      11. @Override

      12. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

      13. if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){

      14. return true;

      15. }

      16. return false;

      17. }

      18. @Override

      19. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

      20. //獲取請(qǐng)求token,如果token不存在,直接返回401

      21. String token = getRequestToken((HttpServletRequest) request);

      22. if(StringUtils.isBlank(token)){

      23. HttpServletResponse httpResponse = (HttpServletResponse) response;

      24. httpResponse.setHeader('Access-Control-Allow-Credentials', 'true');

      25. httpResponse.setHeader('Access-Control-Allow-Origin', HttpContextUtils.getOrigin());

      26. String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, 'invalid token'));

      27. httpResponse.getWriter().print(json);

      28. return false;

      29. }

      30. return executeLogin(request, response);

      31. }

      32. /**

      33. *公眾號(hào):MarkerHub

      34. **/

      35. @Override

      36. protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {

      37. HttpServletResponse httpResponse = (HttpServletResponse) response;

      38. httpResponse.setContentType('application/json;charset=utf-8');

      39. httpResponse.setHeader('Access-Control-Allow-Credentials', 'true');

      40. httpResponse.setHeader('Access-Control-Allow-Origin', HttpContextUtils.getOrigin());

      41. try {

      42. //處理登錄失敗的異常

      43. Throwable throwable = e.getCause() == null ? e : e.getCause();

      44. R r = R.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage());

      45. String json = new Gson().toJson(r);

      46. httpResponse.getWriter().print(json);

      47. } catch (IOException e1) {

      48. }

      49. return false;

      50. }

      51. /**

      52. * 獲取請(qǐng)求的token

      53. */

      54. private String getRequestToken(HttpServletRequest httpRequest){

      55. //從header中獲取token

      56. String token = httpRequest.getHeader('token');

      57. //如果header中不存在token,則從參數(shù)中獲取token

      58. if(StringUtils.isBlank(token)){

      59. token = httpRequest.getParameter('token');

      60. }

      61. return token;

      62. }

      63. }

      在 onAccessDenied方法校驗(yàn)通過(guò)之后執(zhí)行 executeLogin方法完成自動(dòng)登錄!

      9、FormAuthenticationFilter

      基于form表單的賬號(hào)密碼自動(dòng)登錄的過(guò)濾器,我們只需要看這個(gè)方法就明白,和renren-fast的實(shí)現(xiàn)相似:

      1. public class FormAuthenticationFilter extends AuthenticatingFilter {

      2. public static final String DEFAULT_USERNAME_PARAM = 'username';

      3. public static final String DEFAULT_PASSWORD_PARAM = 'password';

      4. public static final String DEFAULT_REMEMBER_ME_PARAM = 'rememberMe';

      5. protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {

      6. String username = getUsername(request);

      7. String password = getPassword(request);

      8. return createToken(username, password, request, response);

      9. }

      10. /**

      11. * 公眾號(hào):MarkerHub

      12. **/

      13. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

      14. if (isLoginRequest(request, response)) {

      15. if (isLoginSubmission(request, response)) {

      16. if (log.isTraceEnabled()) {

      17. log.trace('Login submission detected. Attempting to execute login.');

      18. }

      19. return executeLogin(request, response);

      20. } else {

      21. if (log.isTraceEnabled()) {

      22. log.trace('Login page view.');

      23. }

      24. //allow them to see the login page ;)

      25. return true;

      26. }

      27. } else {

      28. if (log.isTraceEnabled()) {

      29. log.trace('Attempting to access a path which requires authentication. Forwarding to the ' +

      30. 'Authentication url [' + getLoginUrl() + ']');

      31. }

      32. saveRequestAndRedirectToLogin(request, response);

      33. return false;

      34. }

      35. }

      36. }

      onAccessDenied調(diào)用executeLogin方法。默認(rèn)的token是UsernamepasswordToken。

      結(jié)束語(yǔ)

      好了,今天先到這里啦,講了多好內(nèi)置的過(guò)濾器,代碼有點(diǎn)多,你們可以用電腦打開(kāi)文章,然后仔細(xì)研究,并回想自己使用shiro過(guò)濾器的時(shí)候,是不是和我講的場(chǎng)景一樣,結(jié)合起來(lái)。

      這里是MarkerHub,我是呂一明,感謝關(guān)注與支持!

      參考:

      https://www.cnblogs.com/LeeScofiled/p/10511948.html


      (完)

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多