SpringSecurity 表單登錄的實現
表單登錄
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .loginPage("/mylogin.html") .loginProcessingUrl("/doLogin") .defaultSuccessUrl("/index.html") .failureHandler(new MyAuthenticationFailureHandler()) .usernameParameter("uname") .passwordParameter("passwd") .permitAll() .and() .logout() .logoutRequestMatcher(new OrRequestMatcher( new AntPathRequestMatcher("/logout1", "GET"), new AntPathRequestMatcher("/logout2", "POST"))) .invalidateHttpSession(true) .clearAuthentication(true) .defaultLogoutSuccessHandlerFor((req,resp,auth)->{ resp.setContentType("application/json;charset=utf-8"); Map<String, Object> result = new HashMap<>(); result.put("status", 200); result.put("msg", "使用 logout1 註銷成功!"); ObjectMapper om = new ObjectMapper(); String s = om.writeValueAsString(result); resp.getWriter().write(s); },new AntPathRequestMatcher("/logout1","GET")) .defaultLogoutSuccessHandlerFor((req,resp,auth)->{ resp.setContentType("application/json;charset=utf-8"); Map<String, Object> result = new HashMap<>(); result.put("status", 200); result.put("msg", "使用 logout2 註銷成功!"); ObjectMapper om = new ObjectMapper(); String s = om.writeValueAsString(result); resp.getWriter().write(s); },new AntPathRequestMatcher("/logout2","POST")) .and() .csrf().disable(); } }
springSecurity需要自定義配置值 基本都是繼承WebSecurityConfigurerAdapter
- authorizeRequests表示開啟權限配置,.anyRequest().authenticated()表示所有的請求都認證之後才能訪問
- and()方法返回HttpSecurity的實例
- formLogin()表示開啟表單登錄配置
- loginPage 配置登錄頁面地址
- loginProcessingUrl 配置登錄接口地址
- defaultSuccessUrl 登錄成功後的跳轉地址
- failureUrl表示登錄失敗後的跳轉地址
- usernameParameter表示登錄用戶名的參數名
- passwordParameter 登錄mima的參數名
- permitAll()表示和登錄相關的頁面和接口不做攔截 直接通過
其中loginProcessingUrl usernameParameter passwordParameter要和登錄表單的配置一致。
.loginPage("/mylogin.html") // .loginProcessingUrl("/doLogin") .defaultSuccessUrl("/index.html") .failureHandler(new MyAuthenticationFailureHandler()) .usernameParameter("uname") .passwordParameter("passwd")
csrf().disable()表示禁用CSRF防禦功能
登錄成功
用戶登錄成功後除瞭defaultSuccessUrl方法可以實現登錄成功的跳轉之外,successForwardUrl也可以實現登錄成功後的跳轉,
defaultSuccessUrl 和successForwardUrl區別:
- defaultSuccessUrl表示當用戶登錄成功後,會自動重定向到登錄之前的地址,如果用戶本身就是訪問的登錄頁面,登錄成功後就會重定向到defaultSuccessUrl指定頁面
- successForwardUrl不會考慮用戶之前的訪問地址,登錄成功後通過服務器端跳轉到successForwardUrl所指定的頁面。
defaultSuccessUrl是客戶端跳轉重定向,successForwardUrl是通過服務端實現的跳轉。
他們的接口都AuthenticationSuccessHandler
AuthenticationSuccessHandler有三個實現類
SimpleUrlAuthenticationSuccessHandler 繼承 AbstractAuthenticationTargetUrlRequestHandler 通過他的handle方法處理請求
SavedRequestAwareAuthenticationSuccessHandler 在SimpleUrlAuthenticationSuccessHandler基礎上增加瞭請求加緩存的功能,可以記錄之前請求的地址,今兒在登錄成功後重定向到開始訪問的地址。
ForwardAuthenticationSuccessHandler 是服務端的跳轉
SavedRequestAwareAuthenticationSuccessHandler
defaultSuccessUrl 對應的是SavedRequestAwareAuthenticationSuccessHandler
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { SavedRequest savedRequest = this.requestCache.getRequest(request, response); if (savedRequest == null) { super.onAuthenticationSuccess(request, response, authentication); } else { String targetUrlParameter = this.getTargetUrlParameter(); if (!this.isAlwaysUseDefaultTargetUrl() && (targetUrlParameter == null || !StringUtils.hasText(request.getParameter(targetUrlParameter)))) { this.clearAuthenticationAttributes(request); String targetUrl = savedRequest.getRedirectUrl(); this.logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl); this.getRedirectStrategy().sendRedirect(request, response, targetUrl); } else { this.requestCache.removeRequest(request, response); super.onAuthenticationSuccess(request, response, authentication); } } }
- 首先從requestCache中獲取緩存下來的請求 如果沒有獲取到緩存請求,就說明用戶在訪問登錄頁面之前並沒有訪問其他頁面,此時直接調用父類的onAuthenticationSuccess方法來處理,重定向到defaultSuccessUrl指定的地址。
- 獲取targetUrlParameter 拿到target參數後重定向地址。
- 如果targetUrlParameter不存在或者alwaysUseDefaultTargetUrl為true 緩存下來的請求沒有意義,直接調用父類的onAuthenticationSuccess方法完成重定向 。targetUrlParameter存在 則重定向到targetUrlParameter中,alwaysUseDefaultTargetUrl為true 走默認
ForwardAuthenticationSuccessHandler
successForwardUrl對應ForwardAuthenticationSuccessHandler
public class ForwardAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private final String forwardUrl; public ForwardAuthenticationSuccessHandler(String forwardUrl) { Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> { return "'" + forwardUrl + "' is not a valid forward URL"; }); this.forwardUrl = forwardUrl; } public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { request.getRequestDispatcher(this.forwardUrl).forward(request, response); } }
主要調用getRequestDispatcher進行服務端請求轉發
自定義AuthenticationSuccessHandler 實現類
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler{ @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); Map<String, Object> resp = new HashMap<>(); resp.put("status", 200); resp.put("msg", "登錄成功!"); ObjectMapper om = new ObjectMapper(); String s = om.writeValueAsString(resp); response.getWriter().write(s); } }
.successHandler(new MyAuthenticationSuccessHandler())
通過HttpServletResponse對象返回登錄成功的json給前端
登錄失敗
failureUrl表示登錄失敗後的重定向到配置的頁面,重定向是客戶端的跳轉,不方便攜帶請求失敗的異常信息。
failureForwardUrl是服務端的跳轉,可以攜帶登錄異常信息。登錄失敗,自動跳轉回登錄頁面,將錯誤信息展示出來。
他們的配置的是AuthenticationFailureHandler接口的實現類
SimpleUrlAuthenticationFailureHandler
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.security.web.authentication; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.http.HttpStatus; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.util.UrlUtils; import org.springframework.util.Assert; public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler { protected final Log logger = LogFactory.getLog(this.getClass()); private String defaultFailureUrl; private boolean forwardToDestination = false; private boolean allowSessionCreation = true; private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); public SimpleUrlAuthenticationFailureHandler() { } public SimpleUrlAuthenticationFailureHandler(String defaultFailureUrl) { this.setDefaultFailureUrl(defaultFailureUrl); } public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { if (this.defaultFailureUrl == null) { this.logger.debug("No failure URL set, sending 401 Unauthorized error"); response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase()); } else { this.saveException(request, exception); if (this.forwardToDestination) { this.logger.debug("Forwarding to " + this.defaultFailureUrl); request.getRequestDispatcher(this.defaultFailureUrl).forward(request, response); } else { this.logger.debug("Redirecting to " + this.defaultFailureUrl); this.redirectStrategy.sendRedirect(request, response, this.defaultFailureUrl); } } } protected final void saveException(HttpServletRequest request, AuthenticationException exception) { if (this.forwardToDestination) { request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception); } else { HttpSession session = request.getSession(false); if (session != null || this.allowSessionCreation) { request.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception); } } } }
當用戶構造SimpleUrlAuthenticationFailureHandler對象時候傳入defaultFailureUrl,也就是登錄失敗時要跳轉的url。在onAuthenticationFailure方法中
- 如果defaultFailureUrl為null,直接通過response返回異常信息,否則調用saveException
- saveException 如果forwardToDestination為true,表示通過服務器端跳轉回到登錄頁面,此時就把異常信息放到request中。
- 回到onAuthenticationFailure方法,如果forwardToDestination為true,就通過服務器端跳回到登錄頁面,否則重定向到登錄頁面。
自定義AuthenticationFailureHandler實現類
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); Map<String, Object> resp = new HashMap<>(); resp.put("status", 500); resp.put("msg", "登錄失敗!" + exception.getMessage()); ObjectMapper om = new ObjectMapper(); String s = om.writeValueAsString(resp); response.getWriter().write(s); } }
通過HttpServletResponse對象返回登錄失敗的json給前端
註銷登錄
.logout() .logoutUrl("") .logoutRequestMatcher(new OrRequestMatcher( new AntPathRequestMatcher("/logout1", "GET"), new AntPathRequestMatcher("/logout2", "POST"))) .invalidateHttpSession(true) .clearAuthentication(true) .logoutSuccessUrl("")
- logout() 表示開啟註銷登錄配置。
- logoutUrl 指定註銷登錄請求地址,默認GET請求,路徑logout
- invalidateHttpSession 表示是否使session失效,默認為true
- clearAuthentication 表示是否清除認證信息,默認為true
- logoutSuccessUrl 表示註銷登錄後的跳轉地址。
- logoutRequestMatcher 匹配多個註銷登錄
自定義註銷成功的返回內容
.logout() .logoutRequestMatcher(new OrRequestMatcher( new AntPathRequestMatcher("/logout1", "GET"), new AntPathRequestMatcher("/logout2", "POST"))) .invalidateHttpSession(true) .clearAuthentication(true) .defaultLogoutSuccessHandlerFor((req,resp,auth)->{ resp.setContentType("application/json;charset=utf-8"); Map<String, Object> result = new HashMap<>(); result.put("status", 200); result.put("msg", "使用 logout1 註銷成功!"); ObjectMapper om = new ObjectMapper(); String s = om.writeValueAsString(result); resp.getWriter().write(s); },new AntPathRequestMatcher("/logout1","GET")) .defaultLogoutSuccessHandlerFor((req,resp,auth)->{ resp.setContentType("application/json;charset=utf-8"); Map<String, Object> result = new HashMap<>(); result.put("status", 200); result.put("msg", "使用 logout2 註銷成功!"); ObjectMapper om = new ObjectMapper(); String s = om.writeValueAsString(result); resp.getWriter().write(s); },new AntPathRequestMatcher("/logout2","POST")) .and() .csrf().disable();
defaultLogoutSuccessHandlerFor()兩個參數 第一個是註銷成功的回調,第二個是具體的註銷請求。
到此這篇關於SpringSecurity 表單登錄的實現的文章就介紹到這瞭,更多相關SpringSecurity 表單登錄內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- SpringSecurity註銷設置的方法
- Spring security如何重寫Filter實現json登錄
- SpringBoot Security權限控制自定義failureHandler實例
- Spring Security配置多個數據源並添加登錄驗證碼的實例代碼
- springboot+jwt+springSecurity微信小程序授權登錄問題