SpringSecurity certification success, failure analysis principles processor
First of all you need to know it is that, SpringSecurity default successes, failures processor SavedRequestAwareAuthenticationSuccessHandler
and SimpleUrlAuthenticationFailureHandler
; under normal circumstances, a resource request, entering into SpringSecurity authentication, the authentication is successful will jump to be requested resource
SavedRequestAwareAuthenticationSuccessHandler source code analysis
Authentication is successful Processor process: when a user requests an interface will be blocked SpringSecurity. When the user authentication is successful, it will jump to the interface before a user wants to request there
Question: how to know the user's request it?
SavedRequest getRequest(HttpServletRequest request, HttpServletResponse response)
. This method can be cached to the user's request.
Assuming that the user has been successfully authenticated, the authentication is successful then the call flow on the processor are:
AbstractAuthenticationProcessingFilter#successfulAuthentication
> AuthenticationSuccessHandler#onAuthenticationSuccess
>SavedRequestAwareAuthenticationSuccessHandler#onAuthenticationSuccess
SavedRequestAwareAuthenticationSuccessHandler
@Override
//这里是重写了该方法,与父类里的实现不一样了
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
//将用户的原始请求缓存住 放到SavedRequest里
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
return;
}
String targetUrlParameter = getTargetUrlParameter();
if (isAlwaysUseDefaultTargetUrl()
|| (targetUrlParameter != null && StringUtils.hasText(request
.getParameter(targetUrlParameter)))) {
requestCache.removeRequest(request, response);
super.onAuthenticationSuccess(request, response, authentication);
return;
}
//删除可能已存储在服务器中的与身份验证有关的临时数据
clearAuthenticationAttributes(request);
String targetUrl = savedRequest.getRedirectUrl();
logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
//跳转到指定的原用户请求路径
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
Here getRedirectStrategy () is DefaultRedirectStrategy.
DefaultRedirectStrategy
public void sendRedirect(HttpServletRequest request, HttpServletResponse response,
String url) throws IOException {
//处理url
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
redirectUrl = response.encodeRedirectURL(redirectUrl);
if (logger.isDebugEnabled()) {
logger.debug("Redirecting to '" + redirectUrl + "'");
}
//这里执行跳转操作
response.sendRedirect(redirectUrl);
}
SavedRequestAwareAuthenticationSuccessHandler source code analysis
When the onAuthenticationFailure
method is invoked, AuthenticationFailureHandler
based on defaultFailureUrl
the jump path. If defaultFailureUrl
not set, it will send 401 error code and the AuthenticationException
error message related to the client.
If the useForward
property is set, then RequestDispatcher.forware
it will be redirected to the destination rather than jump.
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
//如果默认的错误跳转路径为空
if (defaultFailureUrl == null) {
logger.debug("No failure URL set, sending 401 Unauthorized error");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Authentication Failed: " + exception.getMessage());
}
else {
//保存异常信息
saveException(request, exception);
//如果forwardToDestination属性值为true
if (forwardToDestination) {
logger.debug("Forwarding to " + defaultFailureUrl);
request.getRequestDispatcher(defaultFailureUrl)
.forward(request, response);
}
else {
logger.debug("Redirecting to " + defaultFailureUrl);
redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
}
}
}
//根据forwardToDestination的值 选择性的将错误信息 保存在request[重定向与原请求公用一个request域]中或session中。
protected final void saveException(HttpServletRequest request,
AuthenticationException exception) {
if (forwardToDestination) {
request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
}
else {
HttpSession session = request.getSession(false);
if (session != null || allowSessionCreation) {
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION,
exception);
}
}
}
Custom success, failure processor
Success processor
@Component
@Log
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
log.info("登录成功处理器");
//这种方式 即调用父类的方法 是成功之后跳转到指定url
// super.onAuthenticationSuccess(request, response, authentication);
//下面这种方式 是将认证成功的用户信息打印到控制台
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(authentication));
}
}
}
Processor failure
@Component
@Log
public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
//SpringMVC加载JSON解析工具时 注入的 可以直接用
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.info("登录失败处理器");
//这种方式 即调用父类的方法 是失败之后跳转
// super.onAuthenticationFailure(request, response, exception);
//下面这种方式 是将认证失败的错误信息打印到控制台
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(exception));
}
}
}
Custom authentication processor is added to the SpringSecurity
@Configuration
@EnableWebSecurity
public class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationFailureHandler failureHandler;
@Autowired
private MyAuthenticationSuccessHandler successHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.successHandler(successHandler)
.failureHandler(failureHandler)
.and().authorizeRequests().anyRequest().authenticated();
}
}
Such certification process will be able to come to our own definition of certified processors.
Above, if wrong, please point out thank you.