SpringSecurity学习笔记二

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zyxwvuuvwxyz/article/details/102747149

SpringSecurity认证成功、失败处理器原理分析

首先需要知道的是,SpringSecurity默认的成功、失败处理器是SavedRequestAwareAuthenticationSuccessHandlerSimpleUrlAuthenticationFailureHandler;正常情况下,请求一个资源,在进入到SpringSecurity的认证中,认证成功才会跳转到待请求的资源

SavedRequestAwareAuthenticationSuccessHandler源码分析

认证成功处理器流程:用户请求一个接口时,会被SpringSecurity拦截。当用户认证成功后,才会跳转到之前用户想要请求的接口那里

问题:怎么知道用户的请求呢?
SavedRequest getRequest(HttpServletRequest request, HttpServletResponse response)。这个方法就可以将用户的请求缓存起来。

假设此时用户已经认证成功,那么关于认证成功处理器的调用流程是:
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);
	}

这里的getRedirectStrategy()是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源码分析

onAuthenticationFailure方法被调用时,AuthenticationFailureHandler会根据defaultFailureUrl的路径进行跳转。如果defaultFailureUrl没有设置,那么会发送401错误码和与AuthenticationException有关的错误信息给客户端。
如果useForward属性被设置,那么RequestDispatcher.forware将会重定向到目的地而不是跳转。

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);
			}
		}
	}

自定义成功、失败处理器

成功处理器

@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));
        }
    }
}

失败处理器

@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));
        }
    }
}

将自定义认证处理器加入到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();

    }

}

这样认证过程中 就能走到我们自己定义的认证处理器了。

以上,如有错误,请指出谢谢。

猜你喜欢

转载自blog.csdn.net/zyxwvuuvwxyz/article/details/102747149