Spring Security源码阅读(1)

it2025-01-19  37

Spring Security

文章目录

Spring Security1. 介绍功能 2. 核心组件2.1 核心接口Authentication AuthenticationManagerAuthenticationProviderUserDetails和UserDetailsServiceSecurityContext和SecurityContextHolder 2.2 过滤器链过滤器:UsernamePasswordAuthenticationFilter抽象父类:AbstractAuthenticationProcessingFilter子类:UsernamePasswordAuthenticationFilter 过滤器:FilterSecurityInterceptor 3. 流程4. 入口JWT参考

1. 介绍

为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC(Inversion of Control 控制反转),DI(Dependency Injection 依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。 --百度百科

功能

身份认证和授权支持Servlet API集成支持Spring Web MVC集成其他

2. 核心组件

2.1 核心接口

Authentication

interface Authentication extends Principal, Serializable // 权限信息,比如角色或者权限字符串 Collection<? extends GrantedAuthority> getAuthorities(); // 凭证信息,比如键入的密码 Object getCredentials(); // 额外信息,比如请求附带的IP Object getDetails(); // 认证主体,比如实现DetailServices Object getPrincipal(); // 是否认证标识位 boolean isAuthenticated(); void setAuthenticated(boolean isAuthenticated) abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer private final Collection<GrantedAuthority> authorities; private Object details; private boolean authenticated = false; class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken private final Object principal; private Object credentials;

AuthenticationManager

interface AuthenticationManager Authentication authenticate(Authentication authentication) class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean private List<AuthenticationProvider> providers = Collections.emptyList(); private AuthenticationManager parent; // 其他 // 遍历providers执行authenticate Authentication authenticate(Authentication authentication) {}

AuthenticationProvider

abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware Authentication authenticate(Authentication authentication) { // 1. 获取username // 2. 查缓存 // 3. retrieveUser: 模板方法,子类DaoAuthenticationProvider执行UserDetailsService loadUserByUsername获取UserDetails // 4. pre check:isAccountNonLocked、isEnabled、isAccountNonExpired // 5. 密码检查: additionalAuthenticationChecks // 6. post check: isCredentialsNonExpired // 7. createSuccessAuthentication: 用户名、密码、权限等填充,返回 } class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) { UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); // null,抛异常,否则返回 }

UserDetails和UserDetailsService

关键是获取权限列表

interface UserDetails extends Serializable Collection<? extends GrantedAuthority> getAuthorities(); String getUsername(); String getPassword(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); interface UserDetailsService UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

SecurityContext和SecurityContextHolder

持有Authentication

class SecurityContextHolder // 默认实现: ThreadLocalSecurityContextHolderStrategy private static SecurityContextHolderStrategy strategy; class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>(); class SecurityContextImpl implements SecurityContext private Authentication authentication;

2.2 过滤器链

过滤器链 14:48:21.041 [main] INFO o.s.s.w.DefaultSecurityFilterChain - [,43] - Creating filter chain: any request, [ org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@9679750, org.springframework.security.web.context.SecurityContextPersistenceFilter@77865933, org.springframework.security.web.header.HeaderWriterFilter@18578491, org.springframework.security.web.csrf.CsrfFilter@2373ad99, org.springframework.security.web.authentication.logout.LogoutFilter@f88bfbe, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@5ed4bc, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4364712f, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@9b9a327, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@7f1ef916, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4d18b73a, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@53c6f96d, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@75a0c890, org.springframework.security.web.session.SessionManagementFilter@671c4166, org.springframework.security.web.access.ExceptionTranslationFilter@67064bdc, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@d613308 ]

过滤器:UsernamePasswordAuthenticationFilter

抽象父类:AbstractAuthenticationProcessingFilter

匹配到的url,执行认证

private RequestMatcher requiresAuthenticationRequestMatcher;

例如:

public UsernamePasswordAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); } this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;

认证

private AuthenticationManager authenticationManager;

成功和失败的处理handler,可实现接口自定义处理流程

private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
子类:UsernamePasswordAuthenticationFilter

默认处理post /login。

可extends UsernamePasswordAuthenticationFilter,自定义认证url和登录处理(比如额外的验证码等信息需要处理)

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)

// 1. 请求URL是否为POST: request.getMethod().equals("POST") // 2. 获取用户名和密码: request.getParameter // 3. 获取需要认证的实体: UsernamePasswordAuthenticationToken UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); // 4. 填充detail:比如remoteAddress和sessionId setDetails(request, authRequest); // 5. AuthenticationManager执行authenticate,并返回Authentication:填充权限、(DB)用户信息等 return this.getAuthenticationManager().authenticate(authRequest);

过滤器:FilterSecurityInterceptor

doFilter --> invoke

​ --> super.beforeInvocation(fi);

​ --> super.afterInvocation(token, null);

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public void invoke(FilterInvocation fi) throws IOException, ServletException { if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest) { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } else { // first time this request being called, so perform security checking if (fi.getRequest() != null && observeOncePerRequest) { fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); } InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.finallyInvocation(token); } super.afterInvocation(token, null); } }

3. 流程

关键:

将request请求封装到UsernamePasswordAuthenticationToken

调用authenticationManager.authenticate(authencationToken),得到Authentication authentication

保存到Spring Security:SecurityContextHolder.getContext().setAuthentication(authentication);

缓存存储并返回

输入:用户密码

处理filter: UsernamePasswordAuthenticationFilter

从request获取输入,组装成UsernamePasswordAuthenticationToken

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password);

认证,并返回填充信息的Authentication authResult对象

return this.getAuthenticationManager().authenticate(authRequest);

class ProviderManager implements AuthenticationManager

List<AuthenticationProvider> providers result = provider.authenticate(authentication);

abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider

class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider

UserDetails user = this.userCache.getUserFromCache(username); if (user == null) { cacheWasUsed = false; user = retrieveUser(username, authentication); } preAuthenticationChecks.check(user); additionalAuthenticationChecks(user, authentication); postAuthenticationChecks.check(user); if (!cacheWasUsed) { this.userCache.putUserInCache(user); } return createSuccessAuthentication(principalToReturn, authentication, user); protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) { UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); if (loadedUser == null) { throw new InternalAuthenticationServiceException(".."); } return loadedUser; }

成功or失败:

try { authResult = attemptAuthentication(request, response); if (authResult == null) { return; } } catch (InternalAuthenticationServiceException failed) { logger.error(".."); unsuccessfulAuthentication(request, response, failed); return; } catch (AuthenticationException failed) { unsuccessfulAuthentication(request, response, failed); return; } // Authentication success if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authResult);

success: successHandler.onAuthenticationSuccess(request, response, authResult);

failure: failureHandler.onAuthenticationFailure(request, response, failed);

4. 入口

入口:@EnableWebSecurity @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class }) @EnableGlobalAuthentication @Import(AuthenticationConfiguration.class)

WebSecurityConfiguration AuthenticationConfiguration 生成bean AuthenticationManager authenticationManager

入口:继承WebSecurityConfigurerAdapter

JWT

在3的基础之上:

jwt过滤器:在UsernamePasswordAuthenticationFilter之前过滤

读取token,拿到登录信息,查询缓存,得到认证用户信息,填充到SecurityContextHolder

token刷新

参考

(推荐)SpringSecurity+JWT认证流程解析https://juejin.im/post/6846687598442708999

芋道源码http://www.iocoder.cn/Spring-Security/good-collection/?vip

最新回复(0)