您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~
前面的方法中,除了login()方法能成功,另外兩個都失敗,并不是因為代碼問題,而是Spring Security默認是通過Web頁面來實作頁面邏輯跳轉的,但在前后端分離的開發模式中,頁面跳轉的邏輯后端已經無法直接控制了,而是通過回傳狀態碼由前端來執行跳轉,因此,需要對應用進行改造,
首先自定義認證成功處理器,也就是實作AuthenticationSuccessHandler介面:
/** * 自定義認證成功處理器 * * @author 湘王 */ @Component public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { System.out.println("登錄成功"); // 前后端分離的呼叫方式 response.setStatus(HttpStatus.OK.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("OK"); } }
接著來實作之前沒有的認證失敗處理器AuthenticationFailureHandler:
/** * 自定義認證失敗處理器 * * @author 湘王 */ @Component public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { System.out.println("user or password error"); // 前后端分離的呼叫方式 response.setStatus(HttpStatus.OK.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("user or password error"); } }
再實作登出處理器LogoutSuccessHandler:
/** * 自定義登出處理器 * * @author 湘王 */ @Component public class CustomLogoutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { System.out.println("登出成功"); // 前后端分離的呼叫方式 response.setStatus(HttpStatus.OK.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("OK"); } }
然后修改之前的修改WebSecurityConfiguration,讓過濾器中增加對這幾個處理器的支持:
// 控制邏輯 @Override protected void configure(HttpSecurity http) throws Exception { // 執行UsernamePasswordAuthenticationFilter之前添加攔截過濾 http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests() .anyRequest().authenticated() // 設定自定義認證成功、失敗及登出處理器 .and().formLogin().loginPage("/login") .successHandler(successHandler).failureHandler(failureHandler).permitAll() .and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID") .logoutSuccessHandler(logoutSuccessHandler).permitAll() // 跨域訪問 .and().cors() .and().csrf().disable(); }
現在再次測驗LoginController中的登錄和登出操作,可以看到它們都能成功執行,目前權限已經做到了與Controller中的業務邏輯無關了,
但是僅僅做到登錄、登出操作肯定是不行的,這連Demo都不如,所以接下里,來看看一個比較核心的問題:用戶角色是否有效(不然建角色表干嘛),
先在LoginController類中加入下面兩個方法:
@GetMapping("/admin")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String admin() {
return "admin有ROLE_ADMIN角色";
}
@GetMapping("/manager")
@PreAuthorize("hasRole('ROLE_MANAGER')")
public String manager() {
return "manager有ROLE_MANAGER角色";
}
啟動應用,運行postman時會發現:
1、用admin登錄,訪問localhost:8080/admin正常,但訪問localhost:8080/manager就出現Forbidden錯誤;
2、用manager登錄,訪問localhost:8080/manager正常,而訪問localhost:8080/admin也出現Forbidden錯誤,
這說明用戶角色權限已經起作用了,但顯示Forbidden的方式不夠友好,所以再來增加一個自定義處理器,也就是實作AccessDeniedHandler介面,讓訪問拒絕友好一些:
/** * 自定義訪問被拒絕 * * @author 湘王 */ @Component public class CustomAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException, ServletException { System.out.println("permission denied"); // 前后端分離的呼叫方式 response.setStatus(HttpStatus.OK.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("permission denied"); } }
然后同樣地,要在WebSecurityConfiguration過濾器鏈中增加這個新增的過濾器:
// 控制邏輯 @Override protected void configure(HttpSecurity http) throws Exception { // 執行UsernamePasswordAuthenticationFilter之前添加攔截過濾 http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests() .anyRequest().authenticated() // 設定自定義認證成功、失敗及登出處理器 .and().formLogin().loginPage("/login") .successHandler(successHandler).failureHandler(failureHandler).permitAll() .and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID") .logoutSuccessHandler(logoutSuccessHandler).permitAll() // 配置無權訪問的自定義處理器 .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler) .and().cors() .and().csrf().disable(); }
再用postman進行測驗的時候就能看到,現在的提示現在已經比剛才要友好了,
感謝您的大駕光臨!咨詢技術、產品、運營和管理相關問題,請關注后留言,歡迎騷擾,不勝榮幸~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538293.html
標籤:Java
