对spring security oauth2 的客户端模式的研究。
首要要下载spring security oauth2的源码,源码中有官方的例子,sparklr2 和tonr2。sparklr2模拟授权服务器和资源服务器,tonr2模拟客户端。
在tonr2的index.jsp中加了一行代码:
<li><a href="${base}trusted/message">trusted message</a></li>
然后打开http://localhost/tonr2/ 就可以点击trusted message这个链接,然后就是触发了oauth2的客户端模式的例子。
1.通过mvc的映射先触发了tonr2的SparklrController类的trusted函数。
2.tonr2的WebMvcConfig中已经初始化了SparklrServiceImpl。
3.trusted函数调用SparklrServiceImpl的getTrustedMessage()函数。
4.getTrustedMessage函数中调用trustedClientRestTemplate.getForObject(URI.create(sparklrTrustedMessageURL), String.class);
5.sparklrTrustedMessageURL同样是通过WebMvcConfig中@Value("${sparklrTrustedMessageURL}") String sparklrTrustedMessageURL,来初始化的。
6.trustedClientRestTemplate同样是通过WebMvcConfig中 @Qualifier("trustedClientRestTemplate") RestOperations trustedClientRestTemplate,来初始化的。
7.trustedClientRestTemplate是通过下面代码初始化的,实际上就是个OAuth2RestTemplate对象。
public OAuth2RestTemplate trustedClientRestTemplate() { return new OAuth2RestTemplate(trusted(), new DefaultOAuth2ClientContext()); }8.trustedClientRestTemplate.getForObject 也就是OAuth2RestTemplate.getForObject 这个方法写在他的父类里。
public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables); }9.getForObject 里调用了acceptHeaderRequestCallback,acceptHeaderRequestCallback里调用了AcceptHeaderRequestCallback.
@Override protected ClientHttpRequest createRequest(URI uri, HttpMethod method) throws IOException { OAuth2AccessToken accessToken = getAccessToken(); AuthenticationScheme authenticationScheme = resource.getAuthenticationScheme(); if (AuthenticationScheme.query.equals(authenticationScheme) || AuthenticationScheme.form.equals(authenticationScheme)) { uri = appendQueryParameter(uri, accessToken); } ClientHttpRequest req = super.createRequest(uri, method); if (AuthenticationScheme.header.equals(authenticationScheme)) { authenticator.authenticate(resource, getOAuth2ClientContext(), req); } return req; }
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails resource, AccessTokenRequest request) throws UserRedirectRequiredException, AccessDeniedException { OAuth2AccessToken accessToken = null; OAuth2AccessToken existingToken = null; Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth instanceof AnonymousAuthenticationToken) { if (!resource.isClientOnly()) { throw new InsufficientAuthenticationException( "Authentication is required to obtain an access token (anonymous not allowed)"); } } if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) { existingToken = request.getExistingToken(); if (existingToken == null && clientTokenServices != null) { existingToken = clientTokenServices.getAccessToken(resource, auth); } if (existingToken != null) { if (existingToken.isExpired()) { if (clientTokenServices != null) { clientTokenServices.removeAccessToken(resource, auth); } OAuth2RefreshToken refreshToken = existingToken.getRefreshToken(); if (refreshToken != null) { accessToken = refreshAccessToken(resource, refreshToken, request); } } else { accessToken = existingToken; } } } // Give unauthenticated users a chance to get a token and be redirected if (accessToken == null) { // looks like we need to try to obtain a new token. accessToken = obtainNewAccessTokenInternal(resource, request); if (accessToken == null) { throw new IllegalStateException("An OAuth 2 access token must be obtained or an exception thrown."); } } if (clientTokenServices != null && (resource.isClientOnly() || auth != null && auth.isAuthenticated())) { clientTokenServices.saveAccessToken(resource, auth, accessToken); } return accessToken; }
for (AccessTokenProvider tokenProvider : chain) { if (tokenProvider.supportsResource(details)) { return tokenProvider.obtainAccessToken(details, request); } }
return getRestTemplate().execute(getAccessTokenUri(resource, form), getHttpMethod(), getRequestCallback(resource, form, headers), extractor , form.toSingleValueMap());
tonr2 10:10:12.997 [DEBUG] ClientCredentialsAccessTokenProvider - Retrieving token from http://localhost:80/sparklr2/oauth/token tonr2 10:10:13.027 [DEBUG] RestTemplate - Created POST request for "http://localhost:80/sparklr2/oauth/token" tonr2 10:10:13.028 [DEBUG] ClientCredentialsAccessTokenProvider - Encoding and sending form: {grant_type=[client_credentials], scope=[trust]} sparklr23 10:10:13.050 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/webjars/**' sparklr23 10:10:13.050 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/images/**' sparklr23 10:10:13.050 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/uncache_approvals' sparklr23 10:10:13.050 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/cache_approvals' sparklr23 10:10:13.050 [DEBUG] OrRequestMatcher - Trying to match using Ant [pattern='/oauth/token'] sparklr23 10:10:13.050 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/token' sparklr23 10:10:13.050 [DEBUG] OrRequestMatcher - matched sparklr23 10:10:13.052 [DEBUG] FilterChainProxy - /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' sparklr23 10:10:13.058 [DEBUG] FilterChainProxy - /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' sparklr23 10:10:13.059 [DEBUG] FilterChainProxy - /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter' sparklr23 10:10:13.059 [DEBUG] HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@bb64568 sparklr23 10:10:13.059 [DEBUG] FilterChainProxy - /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter' sparklr23 10:10:13.059 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/logout' sparklr23 10:10:13.059 [DEBUG] FilterChainProxy - /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter' sparklr23 10:10:13.063 [DEBUG] BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'my-client-with-registered-redirect' sparklr23 10:10:13.064 [DEBUG] ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider sparklr23 10:10:13.083 [DEBUG] BasicAuthenticationFilter - Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f3bb37ef: Principal: org.springframework.security.core.userdetails.User@3c4746e1: Username: my-client-with-registered-redirect; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_CLIENT sparklr23 10:10:13.083 [DEBUG] FilterChainProxy - /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' sparklr23 10:10:13.084 [DEBUG] FilterChainProxy - /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' sparklr23 10:10:13.086 [DEBUG] FilterChainProxy - /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' sparklr23 10:10:13.086 [DEBUG] AnonymousAuthenticationFilter - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f3bb37ef: Principal: org.springframework.security.core.userdetails.User@3c4746e1: Username: my-client-with-registered-redirect; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_CLIENT' sparklr23 10:10:13.086 [DEBUG] FilterChainProxy - /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter' sparklr23 10:10:13.086 [DEBUG] CompositeSessionAuthenticationStrategy - Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy@135de411 sparklr23 10:10:13.086 [DEBUG] FilterChainProxy - /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' sparklr23 10:10:13.086 [DEBUG] FilterChainProxy - /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' sparklr23 10:10:13.087 [DEBUG] AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/token' sparklr23 10:10:13.088 [DEBUG] FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated] sparklr23 10:10:13.088 [DEBUG] FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f3bb37ef: Principal: org.springframework.security.core.userdetails.User@3c4746e1: Username: my-client-with-registered-redirect; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_CLIENT sparklr23 10:10:13.096 [DEBUG] AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@51e2ee04, returned: 1 sparklr23 10:10:13.096 [DEBUG] FilterSecurityInterceptor - Authorization successful sparklr23 10:10:13.096 [DEBUG] FilterSecurityInterceptor - RunAsManager did not change Authentication object sparklr23 10:10:13.097 [DEBUG] FilterChainProxy - /oauth/token reached end of additional filter chain; proceeding with original chain sparklr23 10:10:13.108 [DEBUG] FrameworkEndpointHandlerMapping - Looking up handler method for path /oauth/token sparklr23 10:10:13.111 [DEBUG] FrameworkEndpointHandlerMapping - Returning handler method [public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>)] sparklr23 10:10:13.131 [DEBUG] ClientCredentialsTokenGranter - Getting access token for: my-client-with-registered-redirect sparklr23 10:10:13.219 [DEBUG] ExceptionTranslationFilter - Chain processed normally sparklr23 10:10:13.219 [DEBUG] SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed tonr2 10:10:13.227 [DEBUG] RestTemplate - POST request for "http://localhost:80/sparklr2/oauth/token" resulted in 200 (OK) tonr2 10:10:13.415 [DEBUG] HttpMessageConverterExtractor - Reading [interface org.springframework.security.oauth2.common.OAuth2AccessToken] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@4c825fa3]1.第一次请求被BasicAuthenticationFilter拦截,具体内容如下:
String[] tokens = extractAndDecodeHeader(header, request);先将request的header中Authorization参数拿出来。Authorization = Basic xxxxxxxxxxxxxxxxxxxxxxx;格式得,xxxxxxxxxxx是经过base64编码的。上句代码主要是将xxxxxxxxxxx解码。解码出来的内容应该是my-client-with-registered-redirect:nnnnnnnnn;其中my-client-with-registered-redirect是客户端id,是在你客户端配置的时候你自己设置进去的,同样在认证端也要配置,否则系统将认证失败。nnnnnnnnn是token。
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); if (user == null) { cacheWasUsed = false; try { 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); }
public void init(HttpSecurity http) throws Exception { registerDefaultAuthenticationEntryPoint(http); if (passwordEncoder != null) { http.getSharedObject(AuthenticationManagerBuilder.class) .userDetailsService(new ClientDetailsUserDetailsService(clientDetailsService())) .passwordEncoder(passwordEncoder()); } else { http.userDetailsService(new ClientDetailsUserDetailsService(clientDetailsService())); } http.securityContext().securityContextRepository(new NullSecurityContextRepository()).and().csrf().disable() .httpBasic().realmName(realm); }
public InMemoryClientDetailsServiceBuilder inMemory() throws Exception { InMemoryClientDetailsServiceBuilder next = getBuilder().inMemory(); setBuilder(next); return next; }
clients.inMemory().withClient("tonr") .resourceIds(SPARKLR_RESOURCE_ID) .authorizedGrantTypes("authorization_code", "implicit") .authorities("ROLE_CLIENT") .scopes("read", "write") .secret("secret") .and() .withClient("tonr-with-redirect") .resourceIds(SPARKLR_RESOURCE_ID) .authorizedGrantTypes("authorization_code", "implicit") .authorities("ROLE_CLIENT") .scopes("read", "write") .secret("secret") .redirectUris(tonrRedirectUri) .and() .withClient("my-client-with-registered-redirect") .resourceIds(SPARKLR_RESOURCE_ID) .authorizedGrantTypes("authorization_code", "client_credentials") .authorities("ROLE_CLIENT") .scopes("read", "trust") .redirectUris("http://anywhere?key=value")2.第一次请求,被FilterSecurityInterceptor拦截,具体内容如下:
相关推荐
通过研究Sparklr2和Tonr2的实现,开发者可以更好地理解OAuth2的工作原理,以及如何在实际项目中应用Spring Security OAuth2来保护API和实现第三方应用的授权。这对于构建现代Web应用,尤其是涉及到用户数据安全的...
Spring Security OAuth 是一个用于保护RESTful Web服务的框架,它为OAuth 1.0a和OAuth 2.0协议...通过研究Sparklr2和Tonr2这两个示例应用,开发者可以更好地掌握OAuth的实践应用,并提升在构建安全Web服务方面的技能。
Spring Security OAuth2集成短信验证码登录以及第三方登录 Spring Security OAuth2是基于Spring Cloud/Spring Boot环境下使用OAuth2.0的解决方案,为开发者提供了全套的组件来支持OAuth2.0认证。然而,在开发过程中...
通过实现`OAuth2AccessDecisionManager` 和 `OAuth2AuthenticationManager`,我们可以基于用户角色、权限或者自定义逻辑来决定是否允许访问资源。 在实际项目中,我们还需要考虑安全性问题,比如防止CSRF攻击,这...
Spring Security OAuth2 是一个强大的框架,用于为Java应用提供OAuth2和OpenID Connect安全功能。OAuth2是一个授权框架,允许第三方应用在用户许可的情况下访问其受保护的资源,而OpenID Connect则是在OAuth2之上...
Spring Security OAuth2 提供了实现OAuth2协议所需的各种组件,包括授权服务器、资源服务器和客户端。 **1. 授权服务器:** 在Spring Security OAuth2中,授权服务器负责处理用户的登录和授权请求。它会验证用户...
Spring Security OAuth2是一个强大的安全框架,它为Web应用程序提供了安全认证和授权的功能。OAuth2则是一种开放标准,允许用户授权第三方应用访问他们存储在另一服务提供商的数据,而无需分享他们的用户名和密码。...
Spring Security OAuth2.0学习笔记 什么是认证、授权、会话。 ... 基于session认证机制的运作流程。...Spring cloud Security OAuth2包括哪些组件?职责? 分布式系统认证需要解决的问题? 掌握学习方法,掌握思考方式。
在代码中,开发者可能通过注释详细说明了每个步骤的实现,例如如何配置OAuth2客户端信息,如何处理授权回调,以及如何在Spring Security中设置访问控制规则。 此外,标签中提到的“sso”(Single Sign-On)表示这个...
赠送jar包:spring-security-oauth2-2.3.5.RELEASE.jar; 赠送原API文档:spring-security-oauth2-2.3.5.RELEASE-javadoc.jar; 赠送源代码:spring-security-oauth2-2.3.5.RELEASE-sources.jar; 赠送Maven依赖信息...
本篇将深入探讨Spring Security OAuth2如何实现基于密码模式的用户登录以及如何使用数据库和Redis进行Token的存储与管理。 首先,OAuth2是一种授权协议,它允许第三方应用在用户授权的情况下访问受保护的资源。...
spring security oauth2的client演示包tonr2,所有的jar都齐全了
#OAuth2-Defender ##主要技术 Maven Spring Boot Spring Security Spring Security OAuth2.0 MySQL ##修改数据库配置 修改defender-oauth2-authorization\src\main\resources\...
Spring Security OAuth2是一个广泛使用的Java库,用于在Spring应用程序中实现OAuth2协议,提供安全授权服务。OAuth2是一种授权框架,允许第三方应用在用户许可的情况下访问其私有资源,如在社交媒体上的数据。2.0.3....
Spring Security OAuth2.0 是一个广泛使用的Java安全框架,它为构建安全的Web应用程序提供了强大的支持。OAuth2.0是授权框架的一个标准,允许第三方应用在用户授权的情况下访问其私有资源,而无需共享用户的登录凭证...
**Spring Security OAuth2 单点登录详解** Spring Security OAuth2 是一个强大的安全框架,用于构建安全的、基于授权的Web应用程序。它提供了多种安全机制,包括认证、授权、单点登录(Single Sign-On, SSO)等。在...
在Spring Security中,我们可以使用OAuth2提供者模式,创建一个认证服务器,它处理客户端的授权请求,生成访问令牌。常见的OAuth2流程包括授权码(Authorization Code)流、隐式(Implicit)流、客户端凭证(Client ...
Spring boot+Spring Security Oauth2.0,Sprint cloud+Spring Security Oauth2集成。四种认证方式。附带有代码,和案例,案例,还有视频链接。我保证看完就回,如果视频链接失效,评论回复我,我单独再给你一份。
通过授权码流程、密码模式、客户端凭据模式等多种授权类型,OAuth2提供了灵活的授权机制,广泛应用于社交登录、API访问控制等领域。 在课程中,新增的第10+11章可能涵盖了Spring Security与OAuth2的深度整合,这...
在 Spring Security OAuth2 中,需要在 Security 配置文件中配置 OAuth 2.0 的相关参数,例如授权服务器的URL、客户端ID、客户端密钥等。 测试工具(RestEasy) 在 Spring Security OAuth2 中,可以使用 RestEasy ...