国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring Security 進(jìn)階-細(xì)節(jié)總結(jié)

LinkedME2016 / 2114人閱讀

摘要:但是我們最好不要在里面對(duì)他進(jìn)行處理,而是放到配置的權(quán)限異常來處理。記得配置登錄認(rèn)證前和過程中的一些請(qǐng)求不需要身份認(rèn)證。登錄認(rèn)證失敗不能直接拋出錯(cuò)誤,需要向前端響應(yīng)異常。

關(guān)于 Spring Security 的學(xué)習(xí)已經(jīng)告一段落了,剛開始接觸該安全框架感覺很迷茫,總覺得沒有 Shiro 靈活,到后來的深入學(xué)習(xí)和探究才發(fā)現(xiàn)它非常強(qiáng)大。簡(jiǎn)單快速集成,基本不用寫任何代碼,拓展起來也非常靈活和強(qiáng)大。
系統(tǒng)集成

集成完該框架默認(rèn)情況下,系統(tǒng)幫我們生成一個(gè)登陸頁(yè),默認(rèn)除了登陸其他請(qǐng)求都需要進(jìn)行身份認(rèn)證,沒有身份認(rèn)證前的任何操作都會(huì)跳轉(zhuǎn)到默認(rèn)登錄頁(yè)。
默認(rèn)生成的密碼也會(huì)在控制臺(tái)輸出。

簡(jiǎn)單頁(yè)面自定義

接下來我們可能需要自己控制一下權(quán)限,自定義一下登錄界面

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .formLogin()
            .loginPage("/login.html") //自定義登錄界面
            .loginProcessingUrl("/login.action") //指定提交地址
            .defaultSuccessUrl("/main.html") //指定認(rèn)證成功跳轉(zhuǎn)界面
            //.failureForwardUrl("/error.html") //指定認(rèn)證失敗跳轉(zhuǎn)界面(注: 轉(zhuǎn)發(fā)需要與提交登錄請(qǐng)求方式一致)
            .failureUrl("/error.html") //指定認(rèn)證失敗跳轉(zhuǎn)界面(注: 重定向需要對(duì)應(yīng)的方法為 GET 方式)
            .usernameParameter("username") //username
            .passwordParameter("password") //password
            .permitAll()
            .and()
        .logout()
            .logoutUrl("/logout.action") //指定登出的url, controller里面不用寫對(duì)應(yīng)的方法
            .logoutSuccessUrl("/login.html") //登出成功跳轉(zhuǎn)的界面
            .permitAll()
            .and()
        .authorizeRequests()
            .antMatchers("/register*").permitAll() //設(shè)置不需要認(rèn)證的
            .mvcMatchers("/main.html").hasAnyRole("admin")
            .anyRequest().authenticated() //其他的全部需要認(rèn)證
            .and()
        .exceptionHandling()
            .accessDeniedPage("/error.html"); //配置權(quán)限失敗跳轉(zhuǎn)界面 (注: url配置不會(huì)被springmvc異常處理攔截, 但是注解配置springmvc異常機(jī)制可以攔截到)
}

從上面配置可以看出自定義配置可以簡(jiǎn)單地分為四個(gè)模塊(登錄頁(yè)面自定義、登出自定義、權(quán)限指定、異常設(shè)定),每個(gè)模塊都對(duì)應(yīng)著一個(gè)過濾器,詳情請(qǐng)看 Spring Security 進(jìn)階-原理篇

需要注意的是:

配置登錄提交的URL loginProcessingUrl(..)、登出URL logoutUrl(..) 都是對(duì)應(yīng)攔截器的匹配地址,會(huì)在對(duì)應(yīng)的過濾器里面執(zhí)行相應(yīng)的邏輯,不會(huì)執(zhí)行到 Controller 里面的方法。

配置的登錄認(rèn)證成功跳轉(zhuǎn)的URL defaultSuccessUrl(..)、登錄認(rèn)證失敗跳轉(zhuǎn)的URL failureUrl(..)、登錄認(rèn)證失敗轉(zhuǎn)發(fā)的URL failureForwardUrl(..)......以及下面登出和權(quán)限配置的URL 可以是靜態(tài)界面地址,也可以是 Controller 里面對(duì)應(yīng)的方法

這里配置 URL 對(duì)應(yīng)的訪問權(quán)限,訪問失敗不會(huì)被 SpringMVC 的異常方法攔截到,注解配置的可以被攔截到。但是我們最好不要在 SpringMVC 里面對(duì)他進(jìn)行處理,而是放到配置的權(quán)限異常來處理。

登錄身份認(rèn)證失敗跳轉(zhuǎn)對(duì)應(yīng)的地址前會(huì)把異常保存到 request(轉(zhuǎn)發(fā)) 或 session(重定向) 里面,可以通過 key WebAttributes.AUTHENTICATION_EXCEPTION 來取出,但是前提是使用系統(tǒng)提供的身份認(rèn)證異常處理handler SimpleUrlAuthenticationFailureHandler

上面這種配置身份認(rèn)證失敗都會(huì)跳轉(zhuǎn)到登錄頁(yè),權(quán)限失敗會(huì)跳轉(zhuǎn)指定的 URL,沒有配置 URL 則會(huì)響應(yīng) 403 的異常給前端,前提是在使用系統(tǒng)為我們提供的默認(rèn)權(quán)限異常處理handler AccessDeniedHandlerImpl

異步響應(yīng)配置

大多數(shù)開發(fā)情況下都是前后端分離,響應(yīng)也都是異步的,不是上面那種表單界面的響應(yīng)方式,雖然通過上面跳轉(zhuǎn)到URL對(duì)應(yīng)的 Controller 里面的方法也能解決,但是大多數(shù)情況下我們需要的是極度簡(jiǎn)化,這時(shí)候一些自定義的處理 handler 就油然而生。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .formLogin()
            .loginProcessingUrl("/login")
            .successHandler(new AuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    System.out.println("****** 身份認(rèn)證成功 ******");
                    response.setStatus(HttpStatus.OK.value());
                }
            })
            .failureHandler(new AuthenticationFailureHandler() {
                @Override
                public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                    System.out.println("****** 身份認(rèn)證失敗 ******");
                    response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
                }
            })
            .permitAll()
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(new LogoutSuccessHandler() {
                @Override
                public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    System.out.println("****** 登出成功 ******");
                    response.setStatus(HttpStatus.OK.value());
                }
            })
            .permitAll()
            .and()
        .authorizeRequests()
            .antMatchers("/main").hasAnyRole("admin")
            .and()
        .exceptionHandling()
            .authenticationEntryPoint(new AuthenticationEntryPoint() {
                @Override
                public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                    System.out.println("****** 沒有進(jìn)行身份認(rèn)證 ******");
                    response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
                }
            })
            .accessDeniedHandler(new AccessDeniedHandler() {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    System.out.println("****** 沒有權(quán)限 ******");
                    response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
                }
            });
}

注意:

沒有指定登錄界面,那么久需要至少配置兩個(gè) handler,登出失敗 hander logoutSuccessHandler(..),登錄身份認(rèn)證失敗的 handler failureHandler(..),以免默認(rèn)這樣兩個(gè)步驟向不存在的登錄頁(yè)跳轉(zhuǎn)。

配置的登錄身份認(rèn)證失敗 handler failureHandler(..) 和 沒有進(jìn)行身份認(rèn)證的異常 handler authenticationEntryPoint(..),這兩個(gè)有區(qū)別,前者是在認(rèn)證過程中出現(xiàn)異常處理,后者是在訪問需要進(jìn)行身份認(rèn)證的URL時(shí)沒有進(jìn)行身份認(rèn)證異常處理。

自定義身份認(rèn)證過程

開發(fā)的時(shí)候我們需要自己來實(shí)現(xiàn)登錄登出的流程,下面來個(gè)最簡(jiǎn)單的自定義。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(new LogoutSuccessHandler() {
                @Override
                public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    System.out.println("****** 登出成功 ******");
                    response.setStatus(HttpStatus.OK.value());
                }
            })
            .permitAll()
            .and()
        .authorizeRequests()
            .antMatchers("/main").hasAnyRole("admin")
            .and()
        .exceptionHandling()
            .authenticationEntryPoint(new AuthenticationEntryPoint() {
                @Override
                public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                    System.out.println("****** 沒有進(jìn)行身份認(rèn)證 ******");
                    response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
                }
            })
            .accessDeniedHandler(new AccessDeniedHandler() {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    System.out.println("****** 沒有權(quán)限 ******");
                    response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
                }
            })
            .and()
        .addFilterBefore(new LoginFilter(), UsernamePasswordAuthenticationFilter.class);
}

注意:

這里配置了登出,也可以不配置,在自定義登出的 Controller 方法里面進(jìn)行手動(dòng)清空 SecurityContextHolder.clearContext();,但是建議配置,一般登錄和登出最好都在過濾器里面進(jìn)行處理。

添加自定義登錄過濾器,相當(dāng)于配置登錄。

記得配置登錄認(rèn)證前和過程中的一些請(qǐng)求不需要身份認(rèn)證。

自定義登錄過濾器詳情

public class LoginFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        if ("/login".equals(httpServletRequest.getServletPath())) { //開始登錄過程

            String username = httpServletRequest.getParameter("username");
            String password = httpServletRequest.getParameter("password");
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, password);

            //模擬數(shù)據(jù)庫(kù)查出來的
            User.UserBuilder userBuilder = User.withUsername(username);
            userBuilder.password("123");
            userBuilder.roles("user", "admin");
            UserDetails user = userBuilder.build();

            if (user == null) {
                System.out.println("****** 自定義登錄過濾器 該用戶不存在 ******");
                httpServletResponse.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
            }
            if (!user.getUsername().equals(authentication.getPrincipal())) {
                System.out.println("****** 自定義登錄過濾器 賬號(hào)有問題 ******");
                httpServletResponse.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
            }
            if (!user.getPassword().equals(authentication.getCredentials())) {
                System.out.println("****** 自定義登錄過濾器 密碼有問題 ******");
                httpServletResponse.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
            }

            UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user.getUsername(), authentication.getCredentials(), user.getAuthorities());
            result.setDetails(authentication.getDetails());

            //注: 最重要的一步
            SecurityContextHolder.getContext().setAuthentication(result);

            httpServletResponse.setStatus(HttpStatus.OK.value());
        } else  {
            chain.doFilter(request, response);
        }
    }
}

注意:

不是登錄認(rèn)證就接著執(zhí)行下一個(gè)過濾器或其他。

登錄認(rèn)證失敗不能直接拋出錯(cuò)誤,需要向前端響應(yīng)異常。

完成登錄邏輯直接響應(yīng),不需要接著往下執(zhí)行什么。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77491.html

相關(guān)文章

  • Spring Security 進(jìn)階-原理篇

    摘要:過濾器基本都是通過過濾器來完成配置的身份認(rèn)證權(quán)限認(rèn)證以及登出。密碼比對(duì)通過進(jìn)行密碼比對(duì)注可自定義通過獲取通過獲取生成身份認(rèn)證通過后最終返回的記錄認(rèn)證的身份信息 知彼知己方能百戰(zhàn)百勝,用 Spring Security 來滿足我們的需求最好了解其原理,這樣才能隨意拓展,本篇文章主要記錄 Spring Security 的基本運(yùn)行流程。 過濾器 Spring Security 基本都是通過...

    android_c 評(píng)論0 收藏0
  • Spring Security 進(jìn)階-加密篇

    摘要:在中加密是一個(gè)很簡(jiǎn)單卻又不能忽略的模塊,數(shù)據(jù)只有加密起來才更安全,這樣就散算據(jù)庫(kù)密碼泄漏也都是密文。當(dāng)然也可以自定義構(gòu)造方法,來制定用其他的方案進(jìn)行加密。應(yīng)用先示范下使用系統(tǒng)的來演示下簡(jiǎn)單的注入構(gòu)造加密方案 在 Spring Security 中加密是一個(gè)很簡(jiǎn)單卻又不能忽略的模塊,數(shù)據(jù)只有加密起來才更安全,這樣就散算據(jù)庫(kù)密碼泄漏也都是密文。本文分析對(duì)應(yīng)的版本是 5.14。 概念 Spr...

    wanglu1209 評(píng)論0 收藏0
  • Spring Security

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

    keelii 評(píng)論0 收藏0
  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁(yè)左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • Spring之旅第十二站:Spring Security 數(shù)據(jù)存儲(chǔ)、攔截請(qǐng)求 、認(rèn)證用戶、*、

    摘要:?jiǎn)⒂冒踩赃@個(gè)簡(jiǎn)單的默認(rèn)配置指定了如何保護(hù)請(qǐng)求,以及客戶端認(rèn)證用戶的方案。基于數(shù)據(jù)庫(kù)進(jìn)行認(rèn)證用戶數(shù)據(jù)通常會(huì)存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)中,并通過進(jìn)行訪問。必須經(jīng)過認(rèn)證其他所有請(qǐng)求都是允許的,不需要認(rèn)證。要求用戶不僅需要認(rèn)證,還要具備權(quán)限。 Spring Security Spring Security 是基于Spring 應(yīng)用程序提供的聲明式安全保護(hù)的安全框架。Spring Sercurity ...

    YuboonaZhang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

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