`
chenshangge
  • 浏览: 87821 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类

spring-security-oauth2客户端@EnableOauth2Sso注解过滤器整理

 
阅读更多


目前使用 @EnableOauth2Sso注解以及 securityConfiguration 配置 security 拦截器有13道
分别是

    WebAsyncManagerIntegrationFilter
    SecurityContextPersistenceFilter
    HeaderWriterFilter
    CsrfFilter
    CSRFHeaderFilter(自定义的过滤器,添加在CsrfFilter后)
    LogoutFilter
    OAuth2ClientAuthenticationProcessingFilter
    RequestCacheAwareFilter
    SecurityContextHolderAwareRequestFilter
    AnonymousAuthenticationFilter
    SessionManagementFilter
    ExceptionTranslationFilter
    FilterSecurityInterceptor


WebAsyncManagerIntegrationFilter
public final class WebAsyncManagerIntegrationFilter extends OncePerRequestFilter {
	private static final Object CALLABLE_INTERCEPTOR_KEY = new Object();

	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor) asyncManager
				.getCallableInterceptor(CALLABLE_INTERCEPTOR_KEY);
		if (securityProcessingInterceptor == null) {
			asyncManager.registerCallableInterceptor(CALLABLE_INTERCEPTOR_KEY,
					new SecurityContextCallableProcessingInterceptor());
		}

		filterChain.doFilter(request, response);
	}
}

提供了对securityContext和WebAsyncManager的集成。方式是通过SecurityContextCallableProcessingInterceptor的beforeConcurrentHandling(NativeWebRequest, Callable)方法来讲SecurityContext设置到Callable上。
SecurityContextCallableProcessingInterceptor:支持spring mvc Callable集成。当SecurityContextCallableProcessingInterceptor执行preProcess(NativeWebRequest, Callable)方法时将注入的SecurityContext传递给SecurityContextHolder。

SecurityContextPersistenceFilter
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (request.getAttribute(FILTER_APPLIED) != null) {
			// ensure that filter is only applied once per request
			chain.doFilter(request, response);
			return;
		}

		final boolean debug = logger.isDebugEnabled();

		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

		if (forceEagerSessionCreation) {
			HttpSession session = request.getSession();

			if (debug && session.isNew()) {
				logger.debug("Eagerly created session: " + session.getId());
			}
		}

		HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
				response);
		SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

		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);

			if (debug) {
				logger.debug("SecurityContextHolder now cleared, as request processing completed");
			}
		}
	}

SecurityContextPersistenceFilter主要是在SecurityContextRepository中保存更新一个securityContext,并将securityContext给以后的过滤器使用

SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

是通过httpSessionSecurityContextRepository.loadContext()方法 从session中获取securityContext,如果获取不到,则创建一个空的,存到SecurityContextHolder中,提供给后面的过滤器使用。
Finally 方法 将securityContext储存到httpSessionSecurityContextRepository中,此时securityContext是包含后面过滤器产生的authentication数据

HeaderWriterFilter

securityConfiguration配置一些header信息,在这里进行追加到request的header中
public class HeaderWriterFilter extends OncePerRequestFilter {

	/**
	 * Collection of {@link HeaderWriter} instances to write out the headers to the
	 * response .
	 */
	private final List<HeaderWriter> headerWriters;

	/**

	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		for (HeaderWriter factory : headerWriters) {
			factory.writeHeaders(request, response);
		}
		filterChain.doFilter(request, response);
	}

}

例如 实现writeHeaders接口


CsrfFilter
	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		CsrfToken csrfToken = tokenRepository.loadToken(request);
		final boolean missingToken = csrfToken == null;
		if (missingToken) {
			CsrfToken generatedToken = tokenRepository.generateToken(request);
			csrfToken = new SaveOnAccessCsrfToken(tokenRepository, request, response,
					generatedToken);
		}
		request.setAttribute(CsrfToken.class.getName(), csrfToken);
		request.setAttribute(csrfToken.getParameterName(), csrfToken);

		if (!requireCsrfProtectionMatcher.matches(request)) {
			filterChain.doFilter(request, response);
			return;
		}

		String actualToken = request.getHeader(csrfToken.getHeaderName());
		if (actualToken == null) {
			actualToken = request.getParameter(csrfToken.getParameterName());
		}
		if (!csrfToken.getToken().equals(actualToken)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Invalid CSRF token found for "
						+ UrlUtils.buildFullRequestUrl(request));
			}
			if (missingToken) {
				accessDeniedHandler.handle(request, response,
						new MissingCsrfTokenException(actualToken));
			}
			else {
				accessDeniedHandler.handle(request, response,
						new InvalidCsrfTokenException(csrfToken, actualToken));
			}
			return;
		}

		filterChain.doFilter(request, response);
	}


在跨域的场景下,客户端访问服务端会首先发起get请求,这个get请求在到达服务端的时候,服务端的Spring security会有一个过滤 器 CsrfFilter去检查这个请求,如果这个request请求的http header里面的X-CSRF-COOKIE的token值为空的时候,服务端就好自动生成一个 token值放进这个X-CSRF-COOKIE值里面,客户端在get请求的header里面获取到这个值,如果客户端有表单提交的post请求,则要求客户端要 携带这个token值给服务端,在post请求的header里面设置_csrf属性的token值,提交的方式可以是ajax也可以是放在form里面设置hidden 属性的标签里面提交给服务端,服务端就会根据post请求里面携带的token值进行校验,如果跟服务端发送给合法客户端的token值是一样的,那么 这个post请求就可以受理和处理,如果不一样或者为空,就会被拦截。由于恶意第三方可以劫持session id,而很难获取token值,所以起到了 安全的防护作用。

CSRFHeaderFilter
自定义的定义,如果cookie中没有XSRF-TOKEN,则追加




LogoutFilter
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (requiresLogout(request, response)) {
			Authentication auth = SecurityContextHolder.getContext().getAuthentication();

			if (logger.isDebugEnabled()) {
				logger.debug("Logging out user '" + auth
						+ "' and transferring to logout destination");
			}

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

			logoutSuccessHandler.onLogoutSuccess(request, response, auth);

			return;
		}

		chain.doFilter(request, response);
	}


handler.logout(request, response, auth);

调用securityContextLogoutHandler.logout,清除session,清除SecurityContext
public void logout(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) {
		Assert.notNull(request, "HttpServletRequest required");
		if (invalidateHttpSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				logger.debug("Invalidating session: " + session.getId());
				session.invalidate();
			}
		}

		if (clearAuthentication) {
			SecurityContext context = SecurityContextHolder.getContext();
			context.setAuthentication(null);
		}

		SecurityContextHolder.clearContext();
	}



OAuth2ClientAuthenticationProcessingFilter
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException, IOException, ServletException {

		OAuth2AccessToken accessToken;
		try {
			accessToken = restTemplate.getAccessToken();
		} catch (OAuth2Exception e) {
			BadCredentialsException bad = new BadCredentialsException("Could not obtain access token", e);
			publish(new OAuth2AuthenticationFailureEvent(bad));
			throw bad;			
		}
		try {
			OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
			if (authenticationDetailsSource!=null) {
				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, accessToken.getValue());
				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, accessToken.getTokenType());
				result.setDetails(authenticationDetailsSource.buildDetails(request));
			}
			publish(new AuthenticationSuccessEvent(result));
			return result;
		}
		catch (InvalidTokenException e) {
			BadCredentialsException bad = new BadCredentialsException("Could not obtain user details from token", e);
			publish(new OAuth2AuthenticationFailureEvent(bad));
			throw bad;			
		}

	}

	private void publish(ApplicationEvent event) {
		if (eventPublisher!=null) {
			eventPublisher.publishEvent(event);
		}
	}
	


父类AbstractAuthenticationProcessingFilter 中doFilter方法调用attemptAuthentication()


代码
accessToken = restTemplate.getAccessToken();  中,如果用户没有通过认证的code,或者使用code去oauth服务换取token时,code已经失效,会在
AuthorizationCodeAccessTokenProvider的getRedirectForAuthorization中抛出UserRedirectRequiredException e

public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
			throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException,
			OAuth2AccessDeniedException {

		AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) details;

		if (request.getAuthorizationCode() == null) {
			if (request.getStateKey() == null) {
				throw getRedirectForAuthorization(resource, request);
			}
			obtainAuthorizationCode(resource, request);
		}
		return retrieveToken(request, resource, getParametersForTokenRequest(resource, request),
				getHeadersForTokenRequest(request));

	}






RequestCacheAwareFilter
public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		HttpServletRequest wrappedSavedRequest = requestCache.getMatchingRequest(
				(HttpServletRequest) request, (HttpServletResponse) response);

		chain.doFilter(wrappedSavedRequest == null ? request : wrappedSavedRequest,
				response);
	}

优先使用缓存的请求
SecurityContextHolderAwareRequestFilter
SecurityContextHolderAwareRequestWrapper类对request包装的目的主要是实现servlet api的一些接口方法isUserInRole、getRemoteUser

AnonymousAuthenticationFilter


public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {

if (SecurityContextHolder.getContext().getAuthentication() == null) {
SecurityContextHolder.getContext().setAuthentication(
createAuthentication((HttpServletRequest) req));

if (logger.isDebugEnabled()) {
logger.debug("Populated SecurityContextHolder with anonymous token: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
}

chain.doFilter(req, res);
}

如果SecurityContextHolder中securityContext没有认证,则创建一个anonymousAuthenticationToken

SessionManagementFilter
当请求所在的session里没有设置"SPRING_SECURITY_CONTEXT"属性的时候, 才会被这个过滤器拦截. 否则跳到下一个过滤器. 但这个"SPRING_SECURITY_CONTEXT"属性是在用户登录验证完成后就放进session里的(具体参考AbstractAuthenticationProcessingFilter.successfulAuthentication()方法), 所以登录成功后的每一个请求, 它的session里都会有这个属性, 所以就不会被这个过滤器拦截.
有两种情况, 用户发出的请求会被这个过滤器拦截:
1. 当用户重启浏览器, 然后使用remember-me授权成功后, 再直接访问授权后的url. 这时, session里没有了"SPRING_SECURITY_CONTEXT"属性. 那么这个请求会被此过滤器拦截. 这时得到的authentication是RemembermeAuthentication的实例.)
2. 当session因过期而被容器自动销毁时, 若用户继续发出请求, 这个请求会放在一个新的session里, 新session里没有设置"SPRING_SECURITY_CONTEXT"属性, 那么这个请求也会被这个过滤器拦截. 这时得到的authentication是AnonymousAuthentication的实例.


securityContextRepository 是HttpSessionSecurityContextRepository 的实例,第一种的情况的时候,将securityContext固化到redis(目前项目统一使用spring-session整合spring-data-redis)
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (request.getAttribute(FILTER_APPLIED) != null) {
			chain.doFilter(request, response);
			return;
		}

		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

		if (!securityContextRepository.containsContext(request)) {
			Authentication authentication = SecurityContextHolder.getContext()
					.getAuthentication();

			if (authentication != null && !trustResolver.isAnonymous(authentication)) {
				// The user has been authenticated during the current request, so call the
				// session strategy
				try {
					sessionAuthenticationStrategy.onAuthentication(authentication,
							request, response);
				}
				catch (SessionAuthenticationException e) {
					// The session strategy can reject the authentication
					logger.debug(
							"SessionAuthenticationStrategy rejected the authentication object",
							e);
					SecurityContextHolder.clearContext();
					failureHandler.onAuthenticationFailure(request, response, e);

					return;
				}
				// Eagerly save the security context to make it available for any possible
				// re-entrant
				// requests which may occur before the current request completes.
				// SEC-1396.
				securityContextRepository.saveContext(SecurityContextHolder.getContext(),
						request, response);
			}
			else {
				// No security context or authentication present. Check for a session
				// timeout
				if (request.getRequestedSessionId() != null
						&& !request.isRequestedSessionIdValid()) {
					if (logger.isDebugEnabled()) {
						logger.debug("Requested session ID "
								+ request.getRequestedSessionId() + " is invalid.");
					}

					if (invalidSessionStrategy != null) {
						invalidSessionStrategy
								.onInvalidSessionDetected(request, response);
						return;
					}
				}
			}
		}

		chain.doFilter(request, response);
	}

ExceptionTranslationFilter
统一处理之后的过滤抛出异常的过滤器
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		try {
			chain.doFilter(request, response);

			logger.debug("Chain processed normally");
		}
		catch (IOException ex) {
			throw ex;
		}
		catch (Exception ex) {
			// Try to extract a SpringSecurityException from the stacktrace
			Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
			RuntimeException ase = (AuthenticationException) throwableAnalyzer
					.getFirstThrowableOfType(AuthenticationException.class, causeChain);

			if (ase == null) {
				ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(
						AccessDeniedException.class, causeChain);
			}

			if (ase != null) {
				handleSpringSecurityException(request, response, chain, ase);
			}
			else {
				// Rethrow ServletExceptions and RuntimeExceptions as-is
				if (ex instanceof ServletException) {
					throw (ServletException) ex;
				}
				else if (ex instanceof RuntimeException) {
					throw (RuntimeException) ex;
				}

				// Wrap other Exceptions. This shouldn't actually happen
				// as we've already covered all the possibilities for doFilter
				throw new RuntimeException(ex);
			}
		}

在这个过滤器的 try 部分中会继续执行过滤器链中剩余的过滤器,后面会执行的一个过滤器是 FilterSecurityInterceptor,这个过滤器是用来处理授权的,就是验证用户是否有权访问某个资源,如果没有权限,就会抛出 AccessDeniedException,此时就会进入 handleSpringSecurityException 方法执行。
此时会访问 /login ,在OAuth2ClientAuthenticationProcessingFilter过滤器中obtainAccessToken
取不到code 会抛出 UserRedirectRequiredException e,再由OAuth2ClientContextFilter
捕获 UserRedirectRequiredException重定向到oauth服务的
https://oauth.rubikstack.com/oauth/authorize?client_id=xxx&redirect_uri=https://......
	public void doFilter(ServletRequest servletRequest,
			ServletResponse servletResponse, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		request.setAttribute(CURRENT_URI, calculateCurrentUri(request));

		try {
			chain.doFilter(servletRequest, servletResponse);
		} catch (IOException ex) {
			throw ex;
		} catch (Exception ex) {
			// Try to extract a SpringSecurityException from the stacktrace
			Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
			UserRedirectRequiredException redirect = (UserRedirectRequiredException) throwableAnalyzer
					.getFirstThrowableOfType(
							UserRedirectRequiredException.class, causeChain);
			if (redirect != null) {
				redirectUser(redirect, request, response);
			} else {
				if (ex instanceof ServletException) {
					throw (ServletException) ex;
				}
				if (ex instanceof RuntimeException) {
					throw (RuntimeException) ex;
				}
				throw new NestedServletException("Unhandled exception", ex);
			}
		}
	}


FilterSecurityInterceptor
简化授权和访问控制决定,委托一个AccessDecisionManager完成授权的判断
这个filter是filterchain中比较复杂,也是比较核心的过滤器,主要负责授权的工作

public void doFilter(ServletRequest request, ServletResponse response, FilterChin chain)  
        throws IOException, ServletException {  
    //封装request, response, chain,方便参数传递、增加代码阅读性  
    FilterInvocation fi = new FilterInvocation(request, response, chain);  
    invoke(fi);  
} 

主要逻辑
// Attempt authorization
		try {
			this.accessDecisionManager.decide(authenticated, object, attributes);
		}
		catch (AccessDeniedException accessDeniedException) {
			publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
					accessDeniedException));

			throw accessDeniedException;
		}
[color=red]AffirmativeBased:只要有一个voter投同意票,就授权成功 
ConsensusBased:只要投同意票的大于投反对票的,就授权成功 
UnanimousBased:需要一致通过才授权成功[/color]
这里用 [b]AffirmativeBased决策管理器[/b]
public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> 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:
				return;

			case AccessDecisionVoter.ACCESS_DENIED:
				deny++;

				break;

			default:
				break;
			}
		}

		if (deny > 0) {
			throw new AccessDeniedException(messages.getMessage(
					"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
		}

		// To get this far, every AccessDecisionVoter abstained
		checkAllowIfAllAbstainDecisions();
	}

  • 大小: 72.4 KB
  • 大小: 45.5 KB
分享到:
评论
1 楼 GeBron 2017-11-07  
超强,世界第一

相关推荐

    spring-cloud-security例子

    Spring Cloud Security提供了OAuth2客户端和服务端的支持,可以方便地实现OAuth2资源服务器和授权服务器的配置。 四、安全配置 在spring-boot-security-master项目中,安全配置通常在Spring Boot的配置类中完成,...

    spring spring security2.5 jar

    3. **过滤器链**:Spring Security的核心在于其过滤器链,它拦截HTTP请求并应用安全策略。`FilterSecurityInterceptor`是其中的关键组件,负责根据配置的访问规则对请求进行处理。 4. **会话管理**:Spring ...

    spring-security-3.1.0.RC3

    每个过滤器都有特定的职责,如`DelegatingFilterProxy`用于委托给Spring Security的其他过滤器,`HttpServletRequestWrapperFilter`用于包装请求以增加安全性。 2. **身份验证(Authentication)**:当用户尝试访问...

    oauth2.zip

    在Spring Boot中,可以通过`@EnableOAuth2Sso`注解开启OAuth2单点登录支持,或者使用`spring-security-oauth2-client`库进行自定义配置,以获取和刷新令牌,并在请求受保护资源时附带令牌。 3. 实现步骤: - **...

    狂神-spring-security素材.rar

    7. **OAuth2与OpenID Connect集成**:Spring Security 支持OAuth2和OpenID Connect,这两种标准用于第三方应用的授权。这使得用户可以通过单一登录(SSO)在多个应用间无缝切换。 8. **Web安全配置**:Spring ...

    spring-security2.zip

    9. **OAuth2整合**:Spring Security也支持OAuth2,可以与第三方服务进行单点登录(SSO)或其他授权交互。 在“spring-security2”这个压缩包中,我们可能找到一个包含上述概念的实现示例,比如配置类、安全相关...

    spring-boot-security

    - **OAuth2支持**:Spring Security可以与其他OAuth2服务器集成,实现单点登录(Single Sign-On, SSO)。 6. **异常处理** 当用户尝试访问受保护的资源但未通过认证或授权时,Spring Security会抛出相应的异常。...

    springsecurity-github-login-:OAuth实现

    在Spring Boot项目中,这通常通过添加`@EnableOAuth2Sso`注解到配置类来完成,这个注解会自动配置OAuth2客户端和服务端的安全过滤器。我们还需要配置GitHub的客户端ID和秘密,以及重定向URL。 ```java @...

    微信企业号OAuth2验证接口的2种实例(使用SpringMVC)

    2. 使用`@EnableOAuth2Sso`:在主配置类上添加此注解,开启OAuth2单点登录支持。这将自动配置Spring Security的OAuth2过滤器链。 3. 创建Controller:创建一个处理OAuth2授权回调的Controller,使用`@...

    sso-oauth.zip

    本篇文章将深入探讨如何使用Spring Security OAuth来实现一个SSO系统,基于Spring Boot 2.1.3、Spring Security 5.1.4以及Spring Security OAuth 2。 首先,我们需要理解Spring Security的核心概念。Spring ...

    spring security权限管理

    无论是简单的认证和授权,还是复杂的OAuth2、SAML集成,Spring Security都能提供相应的支持。在实际开发中,根据项目需求选择合适的模块和配置,可以确保应用在安全性和易用性之间取得良好的平衡。

    spring-security-in-action

    - Spring Security可以与OAuth2提供商集成,实现第三方登录功能,如Google、Facebook等。 8. **自定义安全逻辑** - 开发者可以自定义身份验证提供者、权限决策管理器、访问决策投票器等,以适应特定的业务需求。 ...

    详解Springboot Oauth2 Server搭建Oauth2认证服务

    - 使用 Spring Security 的 `@EnableOAuth2Sso` 或自定义过滤器处理令牌,以实现用户登录和资源访问。 - 处理授权码流程,当用户同意授权后,获取访问令牌和刷新令牌,并存储在客户端。 7. **测试与部署**: - ...

    spring-security-study

    1. **OAuth2整合**:Spring Security支持OAuth2协议,可实现第三方应用的授权接入。 2. **SSO单点登录**:通过CAS、SAML等方式,实现在多个应用间的一次登录。 3. **自定义认证与授权**:开发人员可以根据需求扩展...

    spring-security-playground

    7. **OAuth2支持**:Spring Security可以与其他OAuth2服务器集成,实现单点登录(SSO)和其他授权功能。 在"spring-security-playground-master"这个压缩包中,可能包含以下内容: - `src/main/java`:项目的Java...

    SpringOne-Using Spring Security 2

    - **过滤器(Filters)**:Spring Security使用一系列过滤器来处理安全性相关的请求; - **认证管理器(Authentication Manager)**:负责验证用户的凭证; - **授权(Authorization)**:根据用户的角色或权限控制...

    【Java-框架-SpringSecurity】单点登录(认证和授权)- 随笔

    SpringSecurity支持多种SSO协议,如CAS(Central Authentication Service)和OAuth2。 ### 三、SSO实现原理 1. **票据(Ticket)机制**:在SSO中,票据是用户身份的临时凭证。当用户成功登录后,服务器会生成一个...

    SpringSecurity Demo

    Spring Security还支持OAuth2协议,允许第三方应用通过获取授权码来访问受保护的资源。这对于构建API或者实现单点登录(Single Sign-On, SSO)的场景非常有用。 **6. CSRF防护** Spring Security内置了跨站请求...

    狂神的SpringSecurity素材.rar

    总的来说,"狂神的SpringSecurity素材.rar"提供的资源涵盖了SpringSecurity的基本概念、配置、权限管理、OAuth2整合以及与Elasticsearch的配合等方面,是深入学习和掌握SpringSecurity的理想资料。无论你是想提升你...

    springsecurity

    `springsecurity-sample`可能是一个示例项目,其中包含了如何配置这些过滤器的实例。 2. **访问控制**:Spring Security提供了基于角色的访问控制(RBAC),允许开发者定义不同角色对资源的访问权限。例如,管理员...

Global site tag (gtag.js) - Google Analytics