`
mengqingyu
  • 浏览: 333025 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

spring-security3(二)源码分析

阅读更多
利用断点走了一遍spring-security源码的核心部分,下面根据自己的理解对源码做了一些解释,过滤器开头的标号是运行时默认配置调用的顺序,理解了原理,我们可以通过继承和实现接口的方式扩展过滤器,权限验证器,数据查询器,投票器等等......

1.SecurityContextPersistenceFilter        从HttpSession中获取SecurityContext上下文
2.logoutFilter                            如果访问地址为/j_spring_security_logout,LogoutFilter将注销用户
3.AbstractAuthenticationProcessingFilter  权限管理器如果访问地址为/j_spring_security_check则选择对应的数据查询器来获取存储的用户相关信息
4.BasicAuthenticationFilter
5.RequestCacheAwareFilter
6.SecurityContextHolderAwareRequestFilter 
7.RememberMeAuthenticationFilter          如果当前SecurityContextHolder中没有用户对象,则通过cookie查找
8.AnonymousAuthenticationFilter           如果当前SecurityContextHolder中没有用户对象,则创建匿名对象
9.SessionManagementFilter                 检查session是否超时
10.ExceptionTranslationFilter             调用FilterSecurityInterceptor,AbstractSecurityInterceptor使用投票器进行权限判断
11.SwitchUserFilter                       用户切换高权限用户向低权限用户切换



//从HttpSession中获取SecurityContext上下文 
public class SecurityContextPersistenceFilter extends GenericFilterBean {

    private SecurityContextRepository repo = new HttpSessionSecurityContextRepository();

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        
		//代码略.....................
		
        HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
        SecurityContext contextBeforeChainExecution = repo.loadContext(holder);//获得security上下文

        try {
            SecurityContextHolder.setContext(contextBeforeChainExecution);

            chain.doFilter(holder.getRequest(), holder.getResponse());//调用下一个过滤器

        } finally {
            SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
            // Crucial removal of SecurityContextHolder contents - do this before anything else.
            SecurityContextHolder.clearContext();
            repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
            request.removeAttribute(FILTER_APPLIED);
        }
    }
	
	//代码略.....................
}

//如果访问地址为/j_spring_security_logout,LogoutFilter将注销用户
public class LogoutFilter extends GenericFilterBean {

    private String filterProcessesUrl = "/j_spring_security_logout"; 
    //代码略.....................
	
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
			
		//判断如果访问地址为/j_spring_security_logout则执行注销,否则跳过
        if (requiresLogout(request, response)) { 
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();

            for (LogoutHandler handler : handlers) {
                handler.logout(request, response, auth);
            }

            logoutSuccessHandler.onLogoutSuccess(request, response, auth);

            return;
        }

        chain.doFilter(request, response);
    }
	
    //代码略.....................
}

//权限管理器如果访问地址为/j_spring_security_check则选择对应的数据查询器来获取存储的用户相关信息
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements
    ApplicationEventPublisherAware, MessageSourceAware {
		
    //代码略.....................
	
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
		throws IOException, ServletException {

		//判断如果访问地址为/j_spring_security_check则跳过进行权限获取和判断,否则执行AnonymousAuthenticationFilter
        if (!requiresAuthentication(request, response)) { 
            chain.doFilter(request, response); //调用下一个过滤器BasicAuthenticationFilter

            return;
        }

        Authentication authResult;

        try {
			//执行UsernamePasswordAuthenticationFilter类中的方法
            authResult = attemptAuthentication(request, response);
            if (authResult == null) {
                // return immediately as subclass has indicated that it hasn't completed authentication
                return;
            }
            sessionStrategy.onAuthentication(authResult, request, response);
        }
        catch (AuthenticationException failed) {
            // Authentication failed
            unsuccessfulAuthentication(request, response, failed);

            return;
        }

        // Authentication success
        if (continueChainBeforeSuccessfulAuthentication) {
            chain.doFilter(request, response);
        }

        successfulAuthentication(request, response, authResult);
	}
	
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
		Authentication authResult) throws IOException, ServletException {

        SecurityContextHolder.getContext().setAuthentication(authResult);

        rememberMeServices.loginSuccess(request, response, authResult); //是否存入cookie

        // Fire event
        if (this.eventPublisher != null) {
            eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
        }

        successHandler.onAuthenticationSuccess(request, response, authResult);//跳转到目标页面
    }
	
	//代码略.....................
}

public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    //代码略.....................
	
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
		//获取页面提交的用户名、密码
        String username = obtainUsername(request);
        String password = obtainPassword(request);

        username = username.trim();

		//封装成token对象
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        //代码略.....................

		//调用AbstractAuthenticationManager类中的方法
        return this.getAuthenticationManager().authenticate(authRequest);
    }
	
	//代码略.....................
}

public abstract class AbstractAuthenticationManager implements AuthenticationManager {

	//代码略.....................
	
    public final Authentication authenticate(Authentication authRequest) throws AuthenticationException {
        try {
            return doAuthentication(authRequest);//调用ProviderManager类中的方法
        } catch (AuthenticationException e) {
            e.setAuthentication(authRequest);

            if (clearExtraInformation) {
                e.clearExtraInformation();
            }

            throw e;
        }
    }
	
	//代码略.....................
}

//权限认证管理器
public class ProviderManager extends AbstractAuthenticationManager implements MessageSourceAware, InitializingBean {
	private List providers = Collections.emptyList();
	private AuthenticationManager parent;
	
	//代码略.....................
	
    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;
            }

            try {
				//调用AbstractUserDetailsAuthenticationProvider类中的方法
                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;
        }

        eventPublisher.publishAuthenticationFailure(lastException, authentication);

        throw lastException;
    }
	
	//代码略.....................
}

//权限查询器
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
    MessageSourceAware {
		
	//代码略.....................
	
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
            messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
                "Only UsernamePasswordAuthenticationToken is supported"));

        // Determine username
        String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();

        boolean cacheWasUsed = true;
        UserDetails user = this.userCache.getUserFromCache(username); //从Ehcache实现的缓存里取userDetail对象

        if (user == null) {
            cacheWasUsed = false;

            try {
				//调用DaoAuthenticationProvider类中的方法
                user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
            } catch (UsernameNotFoundException notFound) {
                logger.debug("User '" + username + "' not found");

                if (hideUserNotFoundExceptions) {
                    throw new BadCredentialsException(messages.getMessage(
                            "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
                } else {
                    throw notFound;
                }
            }

            Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
        }

        try {
            preAuthenticationChecks.check(user); //检查用户是否有效
			//通过页面传入的用户名、密码和数据库中取出的信息对比验证
            additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); 
        } catch (AuthenticationException exception) {
            if (cacheWasUsed) {
                // There was a problem, so try again after checking
                // we're using latest data (i.e. not from the cache)
                cacheWasUsed = false;
                user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
                preAuthenticationChecks.check(user);
                additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
            } else {
                throw exception;
            }
        }

        postAuthenticationChecks.check(user);

        if (!cacheWasUsed) {
            this.userCache.putUserInCache(user); //将用户对象放入缓存
        }

        Object principalToReturn = user;

        if (forcePrincipalAsString) {
            principalToReturn = user.getUsername();
        }

        return createSuccessAuthentication(principalToReturn, authentication, user);
    }
	
	//代码略.....................
}

//数据库查询器
class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{

	private UserDetailsService userDetailsService;
	
	//代码略.....................
	
    protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        UserDetails loadedUser;

        try {
			//获取用户信息,可以通过实现UserDetailsService接口或继承JdbcDaoImpl类来自定义内部实现
            loadedUser = this.getUserDetailsService().loadUserByUsername(username);//调用自定义类UserDetailsServiceImpl的方法
        }
        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;
    }
	
	protected void additionalAuthenticationChecks(UserDetails userDetails,
		UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        Object salt = null;

        if (this.saltSource != null) {
            salt = this.saltSource.getSalt(userDetails);
        }

        if (authentication.getCredentials() == null) {
            logger.debug("Authentication failed: no credentials provided");

            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
                    includeDetailsObject ? userDetails : null);
        }

        String presentedPassword = authentication.getCredentials().toString();
		//判断密码是否一致
        if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
            logger.debug("Authentication failed: password does not match stored value");

            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
                    includeDetailsObject ? userDetails : null);
        }
    }
	
	//代码略.....................
}

//自定义类实现查询接口
public class UserDetailsServiceImpl extends JdbcDaoSupport implements UserDetailsService {

	private String							authoritiesByUsernameQuery;

	private String							usersByUsernameQuery;

	//代码略.....................
	
	public void setAuthoritiesByUsernameQuery(String queryString) {
		authoritiesByUsernameQuery = queryString;
	}
	
	public void setUsersByUsernameQuery(String usersByUsernameQueryString) {
		this.usersByUsernameQuery = usersByUsernameQueryString;
	}
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
       List users = loadUsersByUsername(username); //访问数据库查询用户信息

        if (users.size() == 0) {
            logger.debug("Query returned no results for user '" + username + "'");

            throw new UsernameNotFoundException(
                    messages.getMessage("JdbcDaoImpl.notFound", new Object[]{username}, "Username {0} not found"), username);
        }

        UserDetails user = users.get(0); // contains no GrantedAuthority[]

        Set dbAuthsSet = new HashSet();

        if (enableAuthorities) {
            dbAuthsSet.addAll(loadUserAuthorities(user.getUsername())); //查询用户拥有的角色
        }

        if (enableGroups) {
            dbAuthsSet.addAll(loadGroupAuthorities(user.getUsername()));
        }

        List dbAuths = new ArrayList(dbAuthsSet);

        addCustomAuthorities(user.getUsername(), dbAuths);

        if (dbAuths.size() == 0) {
            logger.debug("User '" + username + "' has no authorities and will be treated as 'not found'");

            throw new UsernameNotFoundException(
                    messages.getMessage("JdbcDaoImpl.noAuthority",
                            new Object[] {username}, "User {0} has no GrantedAuthority"), username);
        }

        return createUserDetails(username, user, dbAuths);//返回实现UserDetails接口的对象,将验证信息封装到此对象中
	}

	protected List loadUsersByUsername(String username) {
		return getJdbcTemplate().query(usersByUsernameQuery, new String[]{
			username}, new RowMapper() {

			@Override
			public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
				String username = rs.getString(1);
				String password = rs.getString(2);
				boolean enabled = rs.getBoolean(3);
				return new userDetailsImpl(username, password, enabled);//返回实现UserDetails接口的对象
			}
		});
	}

	//代码略.....................
}

//用户信息bean,必须实现UserDetails接口
public class userDetailsImpl implements UserDetails {
	//代码略.....................
}

//由ExceptionTranslationFilter过滤器调用来进行权限判断
public abstract class AbstractSecurityInterceptor implements InitializingBean, ApplicationEventPublisherAware,
    MessageSourceAware {

	//代码略.....................
	
    protected InterceptorStatusToken beforeInvocation(Object object) {

		//这里读取配置FilterSecurityInterceptor的SecurityMetadataSource属性来获取配置的角色,这些属性配置了资源的安全设置
        Collection attributes = this.obtainSecurityMetadataSource().getAttributes(object);

        if (attributes == null) {
            if (rejectPublicInvocations) {
                throw new IllegalArgumentException("Secure object invocation " + object +
                        " was denied as public invocations are not allowed via this interceptor. "
                                + "This indicates a configuration error because the "
                                + "rejectPublicInvocations property is set to 'true'");
            }

            publishEvent(new PublicInvocationEvent(object));

            return null; // no further work post-invocation
        }

		//这里从SecurityContextHolder中去取Authentication对象,一般在登录时会放到SecurityContextHolder中去 
        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",
                    "An Authentication object was not found in the SecurityContext"), object, attributes);
        }

		// 如果前面没有处理鉴权,这里需要对鉴权进行处理
        Authentication authenticated = authenticateIfRequired();

        // Attempt authorization
        try {
			//通过投票器判断当前角色是否有权限访问该地址,如果没有权限则抛出异常,调用AffirmativeBased类中的decide的方法
            this.accessDecisionManager.decide(authenticated, object, attributes);
        }
        catch (AccessDeniedException accessDeniedException) {
			//授权不成功向外发布事件
            publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
                    accessDeniedException));

            throw accessDeniedException;
        }
		
        publishEvent(new AuthorizedEvent(object, attributes, authenticated));

        // 这里构建一个RunAsManager来替代当前的Authentication对象,默认情况下使用的是NullRunAsManager会把SecurityContextHolder中的Authentication对象清空
        Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);

        if (runAs == null) {
		
            // no further work post-invocation
            return new InterceptorStatusToken(authenticated, false, attributes, object);
        } else {

            SecurityContextHolder.getContext().setAuthentication(runAs);

            // need to revert to token.Authenticated post-invocation
            return new InterceptorStatusToken(authenticated, true, attributes, object);
        }
    }
	
	//代码略.....................
}

//决策器
public class AffirmativeBased extends AbstractAccessDecisionManager {

	//代码略.....................
	
    public void decide(Authentication authentication, Object object, Collection configAttributes)
        throws AccessDeniedException {
        int deny = 0;

		//依次使用各个投票器进行投票,并对投票结果进行计票 
        for (AccessDecisionVoter voter : getDecisionVoters()) {
            int result = voter.vote(authentication, object, configAttributes);

            if (logger.isDebugEnabled()) {
                logger.debug("Voter: " + voter + ", returned: " + result);
            }
			//这是对投票结果进行处理,如果遇到其中一票通过,那就授权通过,如果是弃权或者反对,那就继续投票
            switch (result) {
            case AccessDecisionVoter.ACCESS_GRANTED: //result:1
                return;

            case AccessDecisionVoter.ACCESS_DENIED: //result:-1
			    //这里对反对票进行计数 
                deny++;

                break;

            default:
                break;
            }
        }
		//如果有反对票,抛出异常,整个授权不通过
        if (deny > 0) {
            throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",
                    "Access is denied"));
        }

        //这里对弃权票进行处理,看看是全是弃权票的决定情况,默认是不通过,由allowIfAllAbstainDecisions变量控制
        checkAllowIfAllAbstainDecisions();
    }
	
	//代码略.....................
}

//角色投票器
public class RoleVoter implements AccessDecisionVoter {
 
	//代码略.....................
	
    public int vote(Authentication authentication, Object object, Collection attributes) {
        int result = ACCESS_ABSTAIN;
        Collection authorities = extractAuthorities(authentication);
		
        for (ConfigAttribute attribute : attributes) {//这里取得资源的安全配置  
            if (this.supports(attribute)) { 
                result = ACCESS_DENIED;

                //这里对资源配置的安全授权级别进行判断,也就是匹配ROLE为前缀的角色配置   
                //遍历每个配置属性,如果其中一个匹配该主体持有的GrantedAuthority,则访问被允许。
				//当前用户拥有的角色集合,当有任何一个角色满足时授予权限
                for (GrantedAuthority authority : authorities) { 
                    if (attribute.getAttribute().equals(authority.getAuthority())) {
                        return ACCESS_GRANTED;
                    }
                }
            }
        }

        return result;
    }

    Collection extractAuthorities(Authentication authentication) {
        return authentication.getAuthorities();
    }
	
	//代码略.....................
}


分享到:
评论

相关推荐

    spring-security-oauth2源码

    Spring Security OAuth2 是一个强大的框架,用于为Java应用提供OAuth2和OpenID Connect...通过阅读和分析`spring-security-oauth-master`中的源码,可以更深入地了解其实现细节,有助于在实际项目中灵活运用和定制。

    spring-security源代码

    这个压缩包文件"spring-security-parent-2.0.4"是Spring Security的2.0.4版本,是一个Eclipse项目,适合开发者直接导入到Eclipse工作空间进行学习和分析。 1. **Spring Security架构**: Spring Security的架构...

    spring-security-oauth2与spring-security-web 3.1.2 源码

    在这个源码分析中,我们将深入探讨`spring-security-web 3.1.2`和`spring-security-oauth2`这两个关键组件。 首先,`spring-security-web`是Spring Security的核心库,它提供了Web应用程序的基本安全功能,如HTTP...

    Spring security oauth源码

    通过分析这些源码,我们可以深入理解OAuth的工作原理,以及Spring Security OAuth如何支持这些功能。同时,Sparklr2和Tonr2示例能帮助我们直观地看到OAuth流程的每个步骤,包括授权、令牌交换和资源访问。 在实际...

    Spring_Security3_源码分析

    总结,Spring Security 3的源码分析是一个深度学习的过程,涵盖了安全领域的多个方面。通过理解其内部工作机制,开发者可以更好地利用这一强大的框架,为应用程序提供安全的保障。同时,源码分析也能帮助开发者解决...

    spring-security3.0.5源码

    通过对`spring-security-3.0.5.RELEASE`源码的分析,我们可以了解每个类和接口的作用,学习如何扩展和配置Spring Security以满足特定需求。这包括理解`@Configuration`和`@EnableGlobalMethodSecurity`注解如何启用...

    spring-security-3.0.3 jar包( 含源码)

    源码分析: 在Spring Security 3.0.3的源码中,开发者可以研究以下关键组件: - `AuthenticationProvider`:处理认证请求的接口,实现它可以自定义认证逻辑。 - `FilterSecurityInterceptor`:AOP拦截器,负责进行...

    spring-security3.1源码

    3. **Filter安全链**:Spring Security 的Web安全功能主要通过一系列过滤器实现,这些过滤器构成了安全链。其中关键的过滤器有`DelegatingFilterProxy`、`ChannelProcessingFilter`、`...

    spring-security-3.2.9和spring-framework-3.2.4的jar包和源码

    Spring Security和Spring Framework是Java开发中的两个核心组件,它们在构建安全、可扩展的企业级应用程序中扮演着重要角色。这两个库都是Spring生态系统的一...同时,源码分析也是提升编程技巧和解决问题的有效途径。

    spring-security-3.1.x.zip 源码下载

    4. **源码分析**: 通过源码可以深入了解Spring Security的工作流程,例如: - 查看`AbstractAuthenticationProcessingFilter`,了解如何处理登录请求。 - 分析`FilterSecurityInterceptor`,理解授权过程中的...

    spring-security-web-3 source code

    《深入剖析Spring Security Web 3源码...总结,通过对`spring-security-web-3`源码的分析,开发者不仅可以掌握Spring Security的内在工作原理,还能提升解决实际安全问题的能力,为构建更安全的Web应用提供坚实的基础。

    spring-security-samples-contacts-3.1.3 源码实例

    通过源码分析,可以了解这些机制的工作原理。 7. **国际化与错误处理** Spring Security的错误页面和消息都支持国际化,便于不同语言环境下的使用。源码中包含了错误处理逻辑和国际化配置。 8. **自定义扩展** ...

    Spring-Security安全权限管理手册+源码

    `springsecurity-sample.rar` 可能包含一个示例项目,展示如何集成 Spring Security 并进行基本配置。这个样本项目可能包括以下部分: 1. **SecurityConfig**: 定义安全规则的 Java 类,可能使用 `@...

    spring security 3.1.3 源码含sample源码

    综上,Spring Security 3.1.3源码的分析和学习,可以帮助开发者深入理解Web安全原理,掌握如何利用这个强大的框架来保护应用程序免受攻击。通过对源码的研究,可以更清晰地了解其内部工作方式,从而更好地进行定制化...

    Spring_Security源码分析

    在这个源码分析中,我们将聚焦于 `ConfigAttributeDefinition` 类,它是Spring Security配置核心组件的一部分。 `ConfigAttributeDefinition` 类扮演着配置属性的容器角色。它用于封装一系列的 `ConfigAttribute` ...

    spring-security 3.02 jar包及源码.rar

    源码分析可以帮助我们深入理解Spring Security的工作原理,包括它如何处理认证、授权、过滤请求、会话管理等。通过对源码的学习,开发者可以更有效地定制和优化Spring Security以满足特定的应用场景需求。例如,你...

    Spring-Security安全权限管理手册(有源码).rar

    6. **源码分析**:"Spring-Security安全权限管理手册.pdf"可能包含了对Spring Security框架的深入解析,包括其架构设计、核心类的使用方法以及最佳实践等。而"springsecurity-sample.rar"则可能是包含示例代码的...

    spring-security源码,直接引用这个压缩文件即可

    在分析`spring-security 5.0`的源码时,我们可以深入理解其核心机制,帮助我们更好地使用和扩展该框架。 1. **模块结构**: Spring Security 5.0 的源码包含多个模块,如`core`、`config`、`web`等。`core`模块...

    spring-security-mytest

    源码分析可以帮助我们深入理解Spring Security的工作原理,而“工具”标签则表明它是一种用于提升应用程序安全性的实用工具。 在压缩包中的文件名列表中,我们看到以下几个关键文件: 1. **BaseActionSupport.java...

    spring-security3 入门篇

    4. **源码分析** - **Authentication流程**: 分析AuthenticationProvider是如何验证UserDetails的,以及AuthenticationManager如何协调各个Provider。 - **Filter工作原理**: 深入理解如...

Global site tag (gtag.js) - Google Analytics