上篇文章分析了SpringSecurity基于用户名和密码的认证过程,这篇分析下授权流程;授权主要处理权限问题,比如说用户没有登录,如果直接请求某一个需要权限的接口,处理的过程是怎样的;
1>.DelegatingFilterProxy 的doFilter方法
这个是认证的过滤入口,最终调用的是FilterChainProxy的doFilter方法
2>.FilterChainProxy的doFilter
过滤链涉及了14个filter,如图所示
重要的如图所示,下面一个一个来分析;
3>SecurityContextPersistenceFilter的doFilter
先进行处理的是SecurityContextPersistenceFilter过滤器,关键代码如下所示
这里通过repo.loadContext从请求中获取session,然后将session信息保存在context中,方便接下来的filter直接获取当前的用户信息;如下图所示
readSecurityContextFromSession方法具体实现如下,其实就是从session中获取context信息;
之后返回到SecurityContextPersistenceFilter中,通过SecurityContextHolder.setContext(contextBeforeChainExecution);
设置context信息到contextHolder中;如下所示,可见是将context信息放在了ThreadLocal中,线程安全的;
SecurityContextPersistenceFilter的处理流程就到这里;接下来FilterChainProxy的doFilter会调用下面的filter来处理;
4>ExceptionTranslationFilter的doFilter方法
源码如图所示
这里会继续交给下面的Filter去处理,但是会捕获Filter处理的异常
5>FilterSecurityInterceptor的doFilter方法
这里调用invoke方法来处理,代码如下:
super.beforeInvocation(fi)调用父类AbstractSecurityInterceptor的beforeInvocation,代码如下所示
这里authenticateIfRequired会从上下文中取出context信息,代码如下所示,如果没有认证,则重新认证后存储认证信息;
认证之后调用this.accessDecisionManager.decide(authenticated, object, attributes);来判断当前的请求是否是合法的,具体调用是AffirmativeBased的decide方法,如下所示
这里通过投票来决定是否通过认证,具体可以继续往下断点,最终就是通过el表达式来判断当前的路径是否有权限访问;deny>0抛出AccessDeniedException异常,之后会被上面提到的ExceptionTranslationFilter捕获到,返回未授权异常信息;