spring security 源码解读 1
http://feiyan35488.iteye.com/blog/896733
转载:spring security 源码解读 1博客分类:?- spring系列SecuritySpringmavenBeanWeb
这一阵子看到了security,很感兴趣。于是研究一下,我在javaeye上查了好多相关的文档,收益匪浅,从入门级的配置问题,到源码级的解读都非常不错,但是还要自己在亲自走一遍流程才踏实。
?
我看的security 3.0的源码,原因是 security 2.0 的源码没办法通过maven获取到 。
?
首先 security的控制内容有: url,method,session三种,我项目中用到的只有 url。下面就按url的流程来走。
思路: ?使用filter,过滤所有的url 如 /* 这样,并且这个filter应在最前面,道理就不到说了吧。
?? ? 1》 security使用的 filter是 org.springframework.web.filter.DelegatingFilterProxy类,在spring-web jar中。
?? ? ? ?@Override
Java代码??
- protected?void?initFilterBean()?throws?ServletException?{??
- ????//?If?no?target?bean?name?specified,?use?filter?name.??
- ????<span?style="color:?#ff0000;">if?(this.targetBeanName?==?null)?{??
- ????????this.targetBeanName?=?getFilterName();??
- ????}</span>??
- ??
- ????//?Fetch?Spring?root?application?context?and?initialize?the?delegate?early,??
- ????//?if?possible.?If?the?root?application?context?will?be?started?after?this??
- ????//?filter?proxy,?we'll?have?to?resort?to?lazy?initialization.??
- ????synchronized?(this.delegateMonitor)?{??
- ????????WebApplicationContext?wac?=?findWebApplicationContext();??
- ????????if?(wac?!=?null)?{??
- ????????????this.delegate?=?initDelegate(wac);??
- ????????}??
- ????}??
- }??
- ??
- public?void?doFilter(ServletRequest?request,?ServletResponse?response,?FilterChain?filterChain)??
- ????????throws?ServletException,?IOException?{??
- ??
- ????//?Lazily?initialize?the?delegate?if?necessary.??
- ????Filter?delegateToUse?=?null;??
- ????synchronized?(this.delegateMonitor)?{??
- ????????if?(this.delegate?==?null)?{??
- ????????????WebApplicationContext?wac?=?findWebApplicationContext();??
- ????????????if?(wac?==?null)?{??
- ????????????????throw?new?IllegalStateException("No?WebApplicationContext?found:??
- ???????????????????????????????????????????????no?ContextLoaderListener?registered?");??
- ????????????}??
- ????????????this.delegate?=?initDelegate(wac);??
- ????????????????????????????????????//?该方法中的?代码??
- ???????????????????????????????????//???Filter?delegate?=<span?style="color:?#ff0000;">?wac.getBean(getTargetBeanName(),?Filter.class);</span>??
- ????????}??
- ????????delegateToUse?=?this.delegate;??
- ????}??
- ??
- ????//?Let?the?delegate?perform?the?actual?doFilter?operation.??
- ????invokeDelegate(delegateToUse,?request,?response,?filterChain);??
- }??
?
??这里需要注意一点 filter-name 必须为?springSecurityFilterChain,从DelegatingFilterProxy这个名字中可以猜到这只是个代理类(确实如此),当这个类执行时会去取得真正的filter类,这个类在spring容器中默认生成id为?springSecurityFilterChain,在3.0中 该filter 添加了一个 targetName 字段,可以从上面红色代码部分看到它的作用,因此可以通过指定targetName字段,来防止和项目中的其他filter冲突。
?
?? 接下来 该真正的 filterChain出场了,这个类是security事务相关的,应该在security包中。
于是 在 spring-security-web jar中发现了这个类:org.springframeword.security.web.FilterChainProxy ,进去看看可以看出这个就是我要找的类。(关于这一点我是从命名上看出来的,bean的id要和类名保持一致)。
?
?下班了 ,回去再继续添加。
==========================华丽丽的分界线====================================
?
吃完饭 ,继续。
FilterChainProxy 代码:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
?? ? throws IOException, ServletException {
?
?? ? ? ?FilterInvocation fi = new FilterInvocation(request, response, chain);
?? ? ? ?List<Filter> filters = getFilters(fi.getRequestUrl());
?? ? ? ? ? ? ? ? ? ? ? ? ? ?// 根据url 得到需要经过的filters
?? ? ? ? ? ? ? ? ? ? ? ? ? ?// 这里不是很明白,有知道的同学可以留言。
?
?? ? ? ?if (filters == null || filters.size() == 0) { // 如果没有合适的 ,就继续进行filter
?? ? ? ? ? ?if (logger.isDebugEnabled()) {
?? ? ? ? ? ? ? ?logger.debug(fi.getRequestUrl() +
?? ? ? ? ? ? ? ? ? ? ? ?filters == null ? " has no matching filters" : " has an empty filter list");
?? ? ? ? ? ?}
?
?? ? ? ? ? ?chain.doFilter(request, response);
?
?? ? ? ? ? ?return;
?? ? ? ?}
?? ? ? ?//如果有filter 就进行虚拟的filter链。这里并没有跳出容器的 filter链,
?? ? ? ?// 当这个虚拟的filter链完成之后,就继续进行 容器的filter
?? ? ? ?VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters);
?? ? ? ?virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
?? ?}
?接下来就该进行 filterChain了,在security中有好多的filter:
??CHANNEL_FILTER ChannelProcessingFilter?
CONCURRENT_SESSION_FILTER ConcurrentSessionFilter?
SESSION_CONTEXT_INTEGRATION_FILTER HttpSessionContextIntegrationFilter?
LOGOUT_FILTER LogoutFilter?
X509_FILTER X509PreAuthenticatedProcessigFilter?
PRE_AUTH_FILTER Subclass of AstractPreAuthenticatedProcessingFilter?
CAS_PROCESSING_FILTER CasProcessingFilter?
AUTHENTICATION_PROCESSING_FILTER AuthenticationProcessingFilter?
BASIC_PROCESSING_FILTER BasicProcessingFilter?
SERVLET_API_SUPPORT_FILTER classname?
REMEMBER_ME_FILTER RememberMeProcessingFilter?
ANONYMOUS_FILTER AnonymousProcessingFilter?
EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter?
NTLM_FILTER NtlmProcessingFilter?
FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor?
SWITCH_USER_FILTER SwitchUserProcessingFilter 。
?
下面我只分析了 AuthenticationProcessingFilter,这是登录认证处理filter
?public UsernamePasswordAuthenticationFilter() {
?? ? ? ?super("/j_spring_security_check");// 这就是 登录验证的 url。
?? ?}
?
?? ?public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
?? ? ? ?if (postOnly && !request.getMethod().equals("POST")) {
?? ? ? ? ? ?throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
?? ? ? ?} ?// 只允许以post方法 进行认证,能防止一些简单的破解
?
?? ? ? ?String username = obtainUsername(request);
?? ? ? ?String password = obtainPassword(request);
?
?? ? ? ?if (username == null) {
?? ? ? ? ? ?username = "";
?? ? ? ?}
?
?? ? ? ?if (password == null) {
?? ? ? ? ? ?password = "";
?? ? ? ?}
?
?? ? ? ?username = username.trim();
?? ? ? ?// 只是将 username和password封装进去
?? ? ? ?UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
?
?? ? ? ?// Place the last username attempted into HttpSession for views
?? ? ? ?HttpSession session = request.getSession(false);
?
?? ? ? ?if (session != null || getAllowSessionCreation()) {
?? ? ? ? ? ?request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username));
?? ? ? ?}
?
?? ? ? ?// Allow subclasses to set the "details" property
?? ? ? ?setDetails(request, authRequest);
?? ? ? ?// 取得AuthenticationManager 进行认证
?? ? ? ?return this.getAuthenticationManager().authenticate(authRequest);
?? ?}
?
?? ?从request中取得 username,password,封装进 UsernamePasswordAuthenticationToken 中,
?? ?然后将username中写到 session中,这里对username去掉了首尾的空格
?? ?然后调用 AuthenticationManager的 authenticate方法进行具体的认证操作。
?
?? ? public Authentication doAuthentication(Authentication authentication) throws AuthenticationException {
?? ? ? ?Class<? extends Authentication> toTest = authentication.getClass();
?? ? ? ?AuthenticationException lastException = null;
?? ? ? ?Authentication result = null;
?
?? ? ? ?for (AuthenticationProvider provider : getProviders()) {
?
?? ? ? ? ? ?if (!provider.supports(toTest)) {
?? ? ? ? ? ? ? ?continue;
?? ? ? ? ? ?}
?
?? ? ? ? ? ?logger.debug("Authentication attempt using " + provider.getClass().getName());
?
?? ? ? ? ? ?try {
?? ? ? ? ? ? ? ?result = provider.authenticate(authentication);
?
?? ? ? ? ? ? ? ?if (result != null) {
?? ? ? ? ? ? ? ? ? ?copyDetails(authentication, result);
?? ? ? ? ? ? ? ? ? ?break;
?? ? ? ? ? ? ? ?}
?? ? ? ? ? ?} catch (AccountStatusException e) {
?? ? ? ? ? ? ? ?// SEC-546: Avoid polling additional providers if auth failure is due to invalid account status
?? ? ? ? ? ? ? ?eventPublisher.publishAuthenticationFailure(e, authentication);
?? ? ? ? ? ? ? ?throw e;
?? ? ? ? ? ?} catch (AuthenticationException e) {
?? ? ? ? ? ? ? ?lastException = e;
?? ? ? ? ? ?}
?? ? ? ?}
?
?? ? ? ?if (result == null && parent != null) {
?? ? ? ? ? ?// Allow the parent to try.
?? ? ? ? ? ?try {
?? ? ? ? ? ? ? ?result = parent.authenticate(authentication);
?? ? ? ? ? ?} catch (ProviderNotFoundException e) {
?? ? ? ? ? ? ? ?// ignore as we will throw below if no other exception occurred prior to calling parent and the parent
?? ? ? ? ? ? ? ?// may throw ProviderNotFound even though a provider in the child already handled the request
?? ? ? ? ? ?} catch (AuthenticationException e) {
?? ? ? ? ? ? ? ?lastException = e;
?? ? ? ? ? ?}
?? ? ? ?}
?
?? ? ? ?if (result != null) {
?? ? ? ? ? ?if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
?? ? ? ? ? ? ? ?// Authentication is complete. Remove credentials and other secret data from authentication
?? ? ? ? ? ? ? ?((CredentialsContainer)result).eraseCredentials();
?? ? ? ? ? ?}
?
?? ? ? ? ? ?eventPublisher.publishAuthenticationSuccess(result);
?? ? ? ? ? ?return result;
?? ? ? ?}
?
?? ? ? ?// Parent was null, or didn't authenticate (or throw an exception).
?
?? ? ? ?if (lastException == null) {
?? ? ? ? ? ?lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",
?? ? ? ? ? ? ? ? ? ? ? ?new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));
?? ? ? ?}
?
?? ? ? ?eventPublisher.publishAuthenticationFailure(lastException, authentication);
?
?? ? ? ?throw lastException;
?? ?}
?
?? ? 这里对 用户进行认证,成功就发布成功事件,并返回。 失败就发布失败事件,并返回exception
?? ?这里具体的认证过程还是不大熟悉,等再详细的看明白了 再细说。
?? ? 看明白了,authenticationManager可以有多个 provider如 默认的daoAuthenticationProvider 和 ?JaasAuth ,RememmberMeAuth 等
?? ? 下面说 daoAuthenticationProvider 中可以有 ?UserDetailsService ,
?
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
?? ? ? ? ? ?throws AuthenticationException {
?? ? ? ?UserDetails loadedUser;
?
?? ? ? ?try {
?? ? ? ? ? ?loadedUser = this.getUserDetailsService().loadUserByUsername(username);
?? ? ? ?}
?? ? ? ?catch (DataAccessException repositoryProblem) {
?? ? ? ? ? ?throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
?? ? ? ?}
?
?? ? ? ?if (loadedUser == null) {
?? ? ? ? ? ?throw new AuthenticationServiceException(
?? ? ? ? ? ? ? ? ? ?"UserDetailsService returned null, which is an interface contract violation");
?? ? ? ?}
?? ? ? ?return loadedUser;
?? ?}
又通过 userDetailsService.loadUserByUsername() ?,当不存在时 ,返回null
?? ?来得到 UserDetails 这样就能把 整个认证过程理顺了
?
?? 总结一下, ?security 的认证过程能理顺了,对其衔接的过渡代码 还有些拿不准,还有 取得filters的 规则还不是很清楚,还要继续看下去。
?? 已经能理顺了, 在BeanId 类中发现了那些默认的字符串,这样 在spring 解析xml时,遇到 security的标签后,会将这个节点交给 security下的类来执行SecurityNamespaceHandler。
?? 这样就能保证security初始化的正常。包括生成默认的 FilterChainProxy 和添加一些依赖。生成 AuthenticationManager及其依赖的 ProviderManager 等。
??下次,继续看 url资源控制部分
?
- 博客分类:?
- spring系列SecuritySpringmavenBeanWeb
这一阵子看到了security,很感兴趣。于是研究一下,我在javaeye上查了好多相关的文档,收益匪浅,从入门级的配置问题,到源码级的解读都非常不错,但是还要自己在亲自走一遍流程才踏实。
?
我看的security 3.0的源码,原因是 security 2.0 的源码没办法通过maven获取到 。
?
首先 security的控制内容有: url,method,session三种,我项目中用到的只有 url。下面就按url的流程来走。
思路: ?使用filter,过滤所有的url 如 /* 这样,并且这个filter应在最前面,道理就不到说了吧。
?? ? 1》 security使用的 filter是 org.springframework.web.filter.DelegatingFilterProxy类,在spring-web jar中。
?? ? ? ?@Override
Java代码??
- protected?void?initFilterBean()?throws?ServletException?{??
- ????//?If?no?target?bean?name?specified,?use?filter?name.??
- ????<span?style="color:?#ff0000;">if?(this.targetBeanName?==?null)?{??
- ????????this.targetBeanName?=?getFilterName();??
- ????}</span>??
- ??
- ????//?Fetch?Spring?root?application?context?and?initialize?the?delegate?early,??
- ????//?if?possible.?If?the?root?application?context?will?be?started?after?this??
- ????//?filter?proxy,?we'll?have?to?resort?to?lazy?initialization.??
- ????synchronized?(this.delegateMonitor)?{??
- ????????WebApplicationContext?wac?=?findWebApplicationContext();??
- ????????if?(wac?!=?null)?{??
- ????????????this.delegate?=?initDelegate(wac);??
- ????????}??
- ????}??
- }??
- ??
- public?void?doFilter(ServletRequest?request,?ServletResponse?response,?FilterChain?filterChain)??
- ????????throws?ServletException,?IOException?{??
- ??
- ????//?Lazily?initialize?the?delegate?if?necessary.??
- ????Filter?delegateToUse?=?null;??
- ????synchronized?(this.delegateMonitor)?{??
- ????????if?(this.delegate?==?null)?{??
- ????????????WebApplicationContext?wac?=?findWebApplicationContext();??
- ????????????if?(wac?==?null)?{??
- ????????????????throw?new?IllegalStateException("No?WebApplicationContext?found:??
- ???????????????????????????????????????????????no?ContextLoaderListener?registered?");??
- ????????????}??
- ????????????this.delegate?=?initDelegate(wac);??
- ????????????????????????????????????//?该方法中的?代码??
- ???????????????????????????????????//???Filter?delegate?=<span?style="color:?#ff0000;">?wac.getBean(getTargetBeanName(),?Filter.class);</span>??
- ????????}??
- ????????delegateToUse?=?this.delegate;??
- ????}??
- ??
- ????//?Let?the?delegate?perform?the?actual?doFilter?operation.??
- ????invokeDelegate(delegateToUse,?request,?response,?filterChain);??
- }??
?
??这里需要注意一点 filter-name 必须为?springSecurityFilterChain,从DelegatingFilterProxy这个名字中可以猜到这只是个代理类(确实如此),当这个类执行时会去取得真正的filter类,这个类在spring容器中默认生成id为?springSecurityFilterChain,在3.0中 该filter 添加了一个 targetName 字段,可以从上面红色代码部分看到它的作用,因此可以通过指定targetName字段,来防止和项目中的其他filter冲突。
?
?? 接下来 该真正的 filterChain出场了,这个类是security事务相关的,应该在security包中。
于是 在 spring-security-web jar中发现了这个类:org.springframeword.security.web.FilterChainProxy ,进去看看可以看出这个就是我要找的类。(关于这一点我是从命名上看出来的,bean的id要和类名保持一致)。
?
?下班了 ,回去再继续添加。
==========================华丽丽的分界线====================================
?
吃完饭 ,继续。
FilterChainProxy 代码:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
?? ? throws IOException, ServletException {
?
?? ? ? ?FilterInvocation fi = new FilterInvocation(request, response, chain);
?? ? ? ?List<Filter> filters = getFilters(fi.getRequestUrl());
?? ? ? ? ? ? ? ? ? ? ? ? ? ?// 根据url 得到需要经过的filters
?? ? ? ? ? ? ? ? ? ? ? ? ? ?// 这里不是很明白,有知道的同学可以留言。
?
?? ? ? ?if (filters == null || filters.size() == 0) { // 如果没有合适的 ,就继续进行filter
?? ? ? ? ? ?if (logger.isDebugEnabled()) {
?? ? ? ? ? ? ? ?logger.debug(fi.getRequestUrl() +
?? ? ? ? ? ? ? ? ? ? ? ?filters == null ? " has no matching filters" : " has an empty filter list");
?? ? ? ? ? ?}
?
?? ? ? ? ? ?chain.doFilter(request, response);
?
?? ? ? ? ? ?return;
?? ? ? ?}
?? ? ? ?//如果有filter 就进行虚拟的filter链。这里并没有跳出容器的 filter链,
?? ? ? ?// 当这个虚拟的filter链完成之后,就继续进行 容器的filter
?? ? ? ?VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters);
?? ? ? ?virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
?? ?}
?接下来就该进行 filterChain了,在security中有好多的filter:
??CHANNEL_FILTER ChannelProcessingFilter?
CONCURRENT_SESSION_FILTER ConcurrentSessionFilter?
SESSION_CONTEXT_INTEGRATION_FILTER HttpSessionContextIntegrationFilter?
LOGOUT_FILTER LogoutFilter?
X509_FILTER X509PreAuthenticatedProcessigFilter?
PRE_AUTH_FILTER Subclass of AstractPreAuthenticatedProcessingFilter?
CAS_PROCESSING_FILTER CasProcessingFilter?
AUTHENTICATION_PROCESSING_FILTER AuthenticationProcessingFilter?
BASIC_PROCESSING_FILTER BasicProcessingFilter?
SERVLET_API_SUPPORT_FILTER classname?
REMEMBER_ME_FILTER RememberMeProcessingFilter?
ANONYMOUS_FILTER AnonymousProcessingFilter?
EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter?
NTLM_FILTER NtlmProcessingFilter?
FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor?
SWITCH_USER_FILTER SwitchUserProcessingFilter 。
?
下面我只分析了 AuthenticationProcessingFilter,这是登录认证处理filter
?public UsernamePasswordAuthenticationFilter() {
?? ? ? ?super("/j_spring_security_check");// 这就是 登录验证的 url。
?? ?}
?
?? ?public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
?? ? ? ?if (postOnly && !request.getMethod().equals("POST")) {
?? ? ? ? ? ?throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
?? ? ? ?} ?// 只允许以post方法 进行认证,能防止一些简单的破解
?
?? ? ? ?String username = obtainUsername(request);
?? ? ? ?String password = obtainPassword(request);
?
?? ? ? ?if (username == null) {
?? ? ? ? ? ?username = "";
?? ? ? ?}
?
?? ? ? ?if (password == null) {
?? ? ? ? ? ?password = "";
?? ? ? ?}
?
?? ? ? ?username = username.trim();
?? ? ? ?// 只是将 username和password封装进去
?? ? ? ?UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
?
?? ? ? ?// Place the last username attempted into HttpSession for views
?? ? ? ?HttpSession session = request.getSession(false);
?
?? ? ? ?if (session != null || getAllowSessionCreation()) {
?? ? ? ? ? ?request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username));
?? ? ? ?}
?
?? ? ? ?// Allow subclasses to set the "details" property
?? ? ? ?setDetails(request, authRequest);
?? ? ? ?// 取得AuthenticationManager 进行认证
?? ? ? ?return this.getAuthenticationManager().authenticate(authRequest);
?? ?}
?
?? ?从request中取得 username,password,封装进 UsernamePasswordAuthenticationToken 中,
?? ?然后将username中写到 session中,这里对username去掉了首尾的空格
?? ?然后调用 AuthenticationManager的 authenticate方法进行具体的认证操作。
?
?? ? public Authentication doAuthentication(Authentication authentication) throws AuthenticationException {
?? ? ? ?Class<? extends Authentication> toTest = authentication.getClass();
?? ? ? ?AuthenticationException lastException = null;
?? ? ? ?Authentication result = null;
?
?? ? ? ?for (AuthenticationProvider provider : getProviders()) {
?
?? ? ? ? ? ?if (!provider.supports(toTest)) {
?? ? ? ? ? ? ? ?continue;
?? ? ? ? ? ?}
?
?? ? ? ? ? ?logger.debug("Authentication attempt using " + provider.getClass().getName());
?
?? ? ? ? ? ?try {
?? ? ? ? ? ? ? ?result = provider.authenticate(authentication);
?
?? ? ? ? ? ? ? ?if (result != null) {
?? ? ? ? ? ? ? ? ? ?copyDetails(authentication, result);
?? ? ? ? ? ? ? ? ? ?break;
?? ? ? ? ? ? ? ?}
?? ? ? ? ? ?} catch (AccountStatusException e) {
?? ? ? ? ? ? ? ?// SEC-546: Avoid polling additional providers if auth failure is due to invalid account status
?? ? ? ? ? ? ? ?eventPublisher.publishAuthenticationFailure(e, authentication);
?? ? ? ? ? ? ? ?throw e;
?? ? ? ? ? ?} catch (AuthenticationException e) {
?? ? ? ? ? ? ? ?lastException = e;
?? ? ? ? ? ?}
?? ? ? ?}
?
?? ? ? ?if (result == null && parent != null) {
?? ? ? ? ? ?// Allow the parent to try.
?? ? ? ? ? ?try {
?? ? ? ? ? ? ? ?result = parent.authenticate(authentication);
?? ? ? ? ? ?} catch (ProviderNotFoundException e) {
?? ? ? ? ? ? ? ?// ignore as we will throw below if no other exception occurred prior to calling parent and the parent
?? ? ? ? ? ? ? ?// may throw ProviderNotFound even though a provider in the child already handled the request
?? ? ? ? ? ?} catch (AuthenticationException e) {
?? ? ? ? ? ? ? ?lastException = e;
?? ? ? ? ? ?}
?? ? ? ?}
?
?? ? ? ?if (result != null) {
?? ? ? ? ? ?if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
?? ? ? ? ? ? ? ?// Authentication is complete. Remove credentials and other secret data from authentication
?? ? ? ? ? ? ? ?((CredentialsContainer)result).eraseCredentials();
?? ? ? ? ? ?}
?
?? ? ? ? ? ?eventPublisher.publishAuthenticationSuccess(result);
?? ? ? ? ? ?return result;
?? ? ? ?}
?
?? ? ? ?// Parent was null, or didn't authenticate (or throw an exception).
?
?? ? ? ?if (lastException == null) {
?? ? ? ? ? ?lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",
?? ? ? ? ? ? ? ? ? ? ? ?new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));
?? ? ? ?}
?
?? ? ? ?eventPublisher.publishAuthenticationFailure(lastException, authentication);
?
?? ? ? ?throw lastException;
?? ?}
?
?? ? 这里对 用户进行认证,成功就发布成功事件,并返回。 失败就发布失败事件,并返回exception
?? ?这里具体的认证过程还是不大熟悉,等再详细的看明白了 再细说。
?? ? 看明白了,authenticationManager可以有多个 provider如 默认的daoAuthenticationProvider 和 ?JaasAuth ,RememmberMeAuth 等
?? ? 下面说 daoAuthenticationProvider 中可以有 ?UserDetailsService ,
?
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
?? ? ? ? ? ?throws AuthenticationException {
?? ? ? ?UserDetails loadedUser;
?
?? ? ? ?try {
?? ? ? ? ? ?loadedUser = this.getUserDetailsService().loadUserByUsername(username);
?? ? ? ?}
?? ? ? ?catch (DataAccessException repositoryProblem) {
?? ? ? ? ? ?throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
?? ? ? ?}
?
?? ? ? ?if (loadedUser == null) {
?? ? ? ? ? ?throw new AuthenticationServiceException(
?? ? ? ? ? ? ? ? ? ?"UserDetailsService returned null, which is an interface contract violation");
?? ? ? ?}
?? ? ? ?return loadedUser;
?? ?}
又通过 userDetailsService.loadUserByUsername() ?,当不存在时 ,返回null
?? ?来得到 UserDetails 这样就能把 整个认证过程理顺了
?
?? 总结一下, ?security 的认证过程能理顺了,对其衔接的过渡代码 还有些拿不准,还有 取得filters的 规则还不是很清楚,还要继续看下去。
?? 已经能理顺了, 在BeanId 类中发现了那些默认的字符串,这样 在spring 解析xml时,遇到 security的标签后,会将这个节点交给 security下的类来执行SecurityNamespaceHandler。
?? 这样就能保证security初始化的正常。包括生成默认的 FilterChainProxy 和添加一些依赖。生成 AuthenticationManager及其依赖的 ProviderManager 等。
??下次,继续看 url资源控制部分
?
