SpringSecurity 源码解读(一)
来源:互联网 发布:php pc软件开发 编辑:程序博客网 时间:2024/06/06 13:19
由于读官方文档有些技术实在是不能用,所以我开始阅读源代码来进行学习,先从各种项目都会使用到认证拦截器开始
注意,由于笔者还没有对整个SpringSecurity完全掌握,所以只能对常用的流程所用到的代码进行解读,不过肯定是绝大部分的代码
前言:由于这个类太大了,所以这里先叙述常用的部分,内部类等其他不常用的后面会补上,建议读者读前要先对SpringSecurity的运行流程有认识.
小结:1.交给实现类进行认证 2.根据认证结果选择处理器
public abstract class AbstractAuthenticationProcessFilter extends GenericFilterBean implements
ApplicationEventPublisherAware, MessageSourceAware{
public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException,ServletException{
HttpServletRequest request = (ServletRequest) req;
HttpServletResponse response = (ServletResponse) res;
//requeireAuthenetication是这里的一个内部类对象,代码在下面再进行分析,这里可以先理解为判断这个请求是否需要认证,不需要则执行下一个拦截器
if(!requiresAuthentication(request,response){
chain.doFilter(request,response);
return;
}
if(logger.isDebugEnabled()){
logger.debug("Request is to process authentication");
}
//定义一个用于认证的对象,注意,Authentication只是一个接口,它的类型由这个类的实现类决定
Authentication authResult;
try{
//这个方法是抽象方法,由实现类实现,默认实现类是UsenamePasswordAnthenticationFilter
//这个方法完成之后,认证对象就已经完成了认证。
authResult = attemptAuthentication(request,response);
if(authResult == null){
return;
}
//sessionStrategy是NullSessionStrategy的对象,实现类什么都不做,是一个空方法,可以通过setter对SessionStrategy对象进行修改
sessionStrategy.onAuthentication(authResult,request,response);
}catch(InternalAuthenticationServiceException failed){
logger.error("An internal error occurred while trying to anthenticate the user.",failed);
//具体方法在下面,但是不推荐看,涉及的东西太多了
unsuccessfulAnthentication(request,response,failed);
return;
}catch(AuthenticationException failed){
//这是用户自己输入错误,不用写日志
unsuccessfulAnthentication(request,response,failed);
return;
}
//continueChainBeforeSuccessfulAnthentication是谁控制的还不清楚,后面来填坑,默认是false
if(continueChainBeforeSuccessfulAnthentication){
chain.doFilter(request,response);
}
//这里莫名其妙,successfulAuthentication有个方法,四个参数和三个参数的,四个参数就是调用没有chain参数的三个参数的方法..子类可以覆盖
successfulAuthentication(request,response,chain,authResult)
}
//四个参数的省略,就是调用只有三个参数的
protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,Authentication authResult) throws IOException,ServletException{
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
}
//哈哈
SecurityContextHolder.getContext().setAuthentication(authResult);
//这个还要根据remeberMeService中的策略来进行,后面再说
rememberMeServices.loginSuccess(request, response, authResult);
//实现类太多了,不知道是哪个,挖个坑吧,反正不涉及核心
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request,response,authResult);
}
attemptAuthentication和successHandler的流程过长了,下次在说吧。如果本文有什么错误,一定要指出来,我喜欢被人打脸。再见!
番外篇:认证失败时的处理流程
protected void unsuccessfulAnthentication(HttpServletRequest request,HttpServletResponse response,AuthenticationException failed){
//涉及到其他的拦截器,先不说
SecurityContextHolder.clearContext();
if(logger.isDebugEnabled()){
//日志blablabla
logger.debug("Authentication request failed: " + failed.toString());
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler);
}
//这个涉及到rememberMe拦截器,大体就是认证失败删去浏览器中的rememberMeCookie
rememberMeServices.loginFail(request,response);
//failureHandler就是在配置里配置的认证失败处理器对象,默认实现类是SimpleUrlAutheneicationFailureHandler
failureHandler.onAuthenticationFailure(request,response,failed);
}
}
==============================================================================================================================================================
小结:两个判断(1.是否有认证失败跳转的url。2.请求转发还是重定向)
public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler{
protected final Log logger = LogFactory.getLog(getClass());
//认证失败时跳转的页面
private String defaultFailureUrl;
//是否允许创建session
private boolean allowSessionCreation = true;
//这里顺序我微调了一下,方便阅读
//是否直接到目的地址(true即为请求转发,false即为重定向)
private boolean forwardToDestination = false;
//重定向策略(这个类不展开,就是俩方法,计算url和重定向)
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
....构造器略去,这个涉及太多了,后面再说
public void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response,AuthenticationException exception) throws IOException,ServletException{
if(defaultFailureUrl == null){
//没有设置认证失败跳转的URL,那么就直接报401
logger.debug("No failure URL set,sending 401 Unauthorized error");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Authentication Failed:" + exception.getMessage());
}else{
//这个挺好理解,方法在下面
saveException(request,exception);
if(forwardToDestination){
//请求转发
logger.debug("Forwarding to" + defaultFailureUrl);
request.getRequestDispatcher(defaultFailureUrl).forward(request,response);
}else{
//重定向
logger.debug("Redirecting to " + defaultFailureUrl);
redirectStrategy.sendRedirect(request,response,defaultFailureUrl);
}
}
}
protected final void saveException(HttpServletRequest request,AuthenticationException exception){
if(forwardToDestination){
//如果是请求转发,那么把错误放进request中
request.setAttribute(WebAttribute.AUTHENTICATION_EXCEPTION,exception);
}else{
//不是,则把错误存进session中
HttpSession session = request.getSession(false);
if(session != null || allowSessionCreation){
request.getSession.setAttribute(WebAttribute.AUTHENTICATION_EXCEPTION,exception);
}
}
}
}
注意,由于笔者还没有对整个SpringSecurity完全掌握,所以只能对常用的流程所用到的代码进行解读,不过肯定是绝大部分的代码
前言:由于这个类太大了,所以这里先叙述常用的部分,内部类等其他不常用的后面会补上,建议读者读前要先对SpringSecurity的运行流程有认识.
小结:1.交给实现类进行认证 2.根据认证结果选择处理器
public abstract class AbstractAuthenticationProcessFilter extends GenericFilterBean implements
ApplicationEventPublisherAware, MessageSourceAware{
public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException,ServletException{
HttpServletRequest request = (ServletRequest) req;
HttpServletResponse response = (ServletResponse) res;
//requeireAuthenetication是这里的一个内部类对象,代码在下面再进行分析,这里可以先理解为判断这个请求是否需要认证,不需要则执行下一个拦截器
if(!requiresAuthentication(request,response){
chain.doFilter(request,response);
return;
}
if(logger.isDebugEnabled()){
logger.debug("Request is to process authentication");
}
//定义一个用于认证的对象,注意,Authentication只是一个接口,它的类型由这个类的实现类决定
Authentication authResult;
try{
//这个方法是抽象方法,由实现类实现,默认实现类是UsenamePasswordAnthenticationFilter
//这个方法完成之后,认证对象就已经完成了认证。
authResult = attemptAuthentication(request,response);
if(authResult == null){
return;
}
//sessionStrategy是NullSessionStrategy的对象,实现类什么都不做,是一个空方法,可以通过setter对SessionStrategy对象进行修改
sessionStrategy.onAuthentication(authResult,request,response);
}catch(InternalAuthenticationServiceException failed){
logger.error("An internal error occurred while trying to anthenticate the user.",failed);
//具体方法在下面,但是不推荐看,涉及的东西太多了
unsuccessfulAnthentication(request,response,failed);
return;
}catch(AuthenticationException failed){
//这是用户自己输入错误,不用写日志
unsuccessfulAnthentication(request,response,failed);
return;
}
//continueChainBeforeSuccessfulAnthentication是谁控制的还不清楚,后面来填坑,默认是false
if(continueChainBeforeSuccessfulAnthentication){
chain.doFilter(request,response);
}
//这里莫名其妙,successfulAuthentication有个方法,四个参数和三个参数的,四个参数就是调用没有chain参数的三个参数的方法..子类可以覆盖
successfulAuthentication(request,response,chain,authResult)
}
//四个参数的省略,就是调用只有三个参数的
protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,Authentication authResult) throws IOException,ServletException{
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
}
//哈哈
SecurityContextHolder.getContext().setAuthentication(authResult);
//这个还要根据remeberMeService中的策略来进行,后面再说
rememberMeServices.loginSuccess(request, response, authResult);
//实现类太多了,不知道是哪个,挖个坑吧,反正不涉及核心
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request,response,authResult);
}
attemptAuthentication和successHandler的流程过长了,下次在说吧。如果本文有什么错误,一定要指出来,我喜欢被人打脸。再见!
番外篇:认证失败时的处理流程
protected void unsuccessfulAnthentication(HttpServletRequest request,HttpServletResponse response,AuthenticationException failed){
//涉及到其他的拦截器,先不说
SecurityContextHolder.clearContext();
if(logger.isDebugEnabled()){
//日志blablabla
logger.debug("Authentication request failed: " + failed.toString());
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler);
}
//这个涉及到rememberMe拦截器,大体就是认证失败删去浏览器中的rememberMeCookie
rememberMeServices.loginFail(request,response);
//failureHandler就是在配置里配置的认证失败处理器对象,默认实现类是SimpleUrlAutheneicationFailureHandler
failureHandler.onAuthenticationFailure(request,response,failed);
}
}
==============================================================================================================================================================
小结:两个判断(1.是否有认证失败跳转的url。2.请求转发还是重定向)
public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler{
protected final Log logger = LogFactory.getLog(getClass());
//认证失败时跳转的页面
private String defaultFailureUrl;
//是否允许创建session
private boolean allowSessionCreation = true;
//这里顺序我微调了一下,方便阅读
//是否直接到目的地址(true即为请求转发,false即为重定向)
private boolean forwardToDestination = false;
//重定向策略(这个类不展开,就是俩方法,计算url和重定向)
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
....构造器略去,这个涉及太多了,后面再说
public void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response,AuthenticationException exception) throws IOException,ServletException{
if(defaultFailureUrl == null){
//没有设置认证失败跳转的URL,那么就直接报401
logger.debug("No failure URL set,sending 401 Unauthorized error");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Authentication Failed:" + exception.getMessage());
}else{
//这个挺好理解,方法在下面
saveException(request,exception);
if(forwardToDestination){
//请求转发
logger.debug("Forwarding to" + defaultFailureUrl);
request.getRequestDispatcher(defaultFailureUrl).forward(request,response);
}else{
//重定向
logger.debug("Redirecting to " + defaultFailureUrl);
redirectStrategy.sendRedirect(request,response,defaultFailureUrl);
}
}
}
protected final void saveException(HttpServletRequest request,AuthenticationException exception){
if(forwardToDestination){
//如果是请求转发,那么把错误放进request中
request.setAttribute(WebAttribute.AUTHENTICATION_EXCEPTION,exception);
}else{
//不是,则把错误存进session中
HttpSession session = request.getSession(false);
if(session != null || allowSessionCreation){
request.getSession.setAttribute(WebAttribute.AUTHENTICATION_EXCEPTION,exception);
}
}
}
}
阅读全文
0 0
- SpringSecurity 源码解读(一)
- SpringSecurity源码解读(二) successHandler
- SpringSecurity源码学习(一)
- [置顶] SpringSecurity 源码分析一
- SpringSecurity | spring security oauth2.0 配置源码分析(一)
- springsecurity学习(一)
- SpringSecurity应用(一)
- SpringSecurity应用(一)
- springSecurity应用(一)
- SpringSecurity学习(一)
- SpringSecurity源码学习(二)
- SpringSecurity源码学习(三)
- SpringSecurity源码学习(五)
- SpringSecurity源码学习(六)
- HashMap源码解读(一)
- MINA源码解读(一)
- ReactiveCocoa源码解读(一)
- SpringSecurity源码解读(三) AbstractAuthenticationProcessFilter和UsernamePasswordAuthenticationFilter补全
- 选项卡切换(纯Javascript&CSS实现)
- HDU 1069
- 安装opencv出现:cudalegacy/src/graphcuts.cpp:120:54: error: ‘NppiGraphcutState’ has not been declared
- cocos2d基础(1)
- ViewPager_实现无线轮播
- SpringSecurity 源码解读(一)
- PAT乙级1008
- 学习Java EE 总结(第一天)
- mongodb crud
- 最小二乘法
- 20170810Link
- JavaMail邮件发送 工具类
- 关注国情民情,从身边做起
- 51NOD1003 阶乘后0的个数