本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰html
@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()表示全部的請求都認證以後才能訪問java
and()方法返回HttpSecurity的實例web
formLogin()表示開啓表單登陸配置spring
其中loginProcessingUrl usernameParameter passwordParameter要和登陸表單的配置一致。apache
.loginPage("/mylogin.html") //
.loginProcessingUrl("/doLogin")
.defaultSuccessUrl("/index.html")
.failureHandler(new MyAuthenticationFailureHandler())
.usernameParameter("uname")
.passwordParameter("passwd")
複製代碼
csrf().disable()表示禁用CSRF防護功能json
用戶登陸成功後除了defaultSuccessUrl方法能夠實現登陸成功的跳轉以外,successForwardUrl也能夠實現登陸成功後的跳轉,後端
defaultSuccessUrl 和successForwardUrl區別:緩存
defaultSuccessUrl是客戶端跳轉重定向,successForwardUrl是經過服務端實現的跳轉。服務器
他們的接口都AuthenticationSuccessHandler
AuthenticationSuccessHandler有三個實現類
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);
}
}
}
複製代碼
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進行服務端請求轉發
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接口的實現類
//
// 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,就經過服務器端跳回到登陸頁面,不然重定向到登陸頁面。
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()
.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()兩個參數 第一個是註銷成功的回調,第二個是具體的註銷請求。