Spring Boot整合Spring Security简记-O
new無语 转载请注明原创出处,谢谢!
OAuth 2.0 Provider
OAuth 2.0 Provider机制负责暴露OAuth 2.0受保护的资源。配置包括建立独立OAuth 2.0客户端可以访问受保护资源。提供者(Provider)通过管理和验证OAuth 2.0令牌用于访问受保护的资源。在适用情况下,提供者必须提供一个接口,让用户确认客户端有权限访问受保护的资源。
OAuth 2.0 Provider Implementatio
OAuth 2.0提供者角色实际上是分开授权服务和资源服务,虽然有时会在同一个应用程序中,但是使用Spring Security OAuth
,您可以选择将它们拆分为两个应用程序,还可以有多个共享的资源服务授权服务。对令牌的请求由Spring MVC Controller
端点处理,受保护资源的访问由标准的Spring Security
请求过滤器处理。为了实现OAuth 2.0授权服务器,Spring Security
过滤器链中需要以下端点:
-
AuthorizationEndpoint
用于为授权请求提供服务。默认网址:/oauth/authorize
。 -
TokenEndpoint
用于服务访问令牌的请求。默认网址:/oauth/token
。
以下过滤器是实现OAuth 2.0资源服务器所必需的:
- 将
OAuth2AuthenticationProcessingFilter
用于加载给定的认证访问令牌请求的认证。
授权服务器配置
在配置授权服务器时,必须考虑客户端用来从用户获取访问令牌(例如,授权码,用户凭据,刷新令牌)的授予类型。服务器的配置用于提供客户端详细信息服务和令牌服务的实现。
该@EnableAuthorizationServer
注释用于配置的OAuth 2.0授权服务器机制,与任何一起@Beans
实现AuthorizationServerConfigurer
。以下功能委托给由Spring
创建并分配到的配置器AuthorizationServerConfigurer
:
-
ClientDetailsServiceConfigurer
:定义客户端详细信息服务的配置器。客户详细信息可以初始化,或者您可以引用现有的store。 -
AuthorizationServerSecurityConfigurer
:定义令牌端点上的安全约束。 -
AuthorizationServerEndpointsConfigurer
:定义授权和令牌端点以及令牌服务。
提供程序配置的一个重要方面是将授权代码提供给OAuth客户端(在授权代码授权中)的方式。OAuth客户端通过将最终用户导向授权页面来获得授权码,其中用户可以输入其凭证,再从授权服务器重定向到具有授权码的OAuth客户端。
ClientDetailsServiceConfigurer客户端详细信息
ClientDetailsServiceConfigurer
可用于定义一个内存或JDBC客户端的实现服务细节。
重要属性:
-
clientId
:客户端ID。 -
secret
:客户端密钥 -
scope
:客户受限的范围。如果范围未定义或为空(默认),则客户端不受范围的限制。 -
authorizedGrantTypes
:授予客户端使用的授权类型。默认值是空的。 -
authorities
:授予客户的机构。
客户端详细信息可以通过直接访问底层存储(例如数据库表JdbcClientDetailsService
)或通过ClientDetailsManager
接口(这两种实现ClientDetailsService
也可以实现)在正在运行的应用程序中更新。
令牌管理
该AuthorizationServerTokenServices
接口定义了所必需的管理OAuth 2.0令牌的操作。请注意以下几点:
- 创建一个访问令牌时,身份验证必须存储,以便资源接受访问令牌可以引用它。
- 访问令牌用于加载,用于授权其创建的认证。
在创建AuthorizationServerTokenServices
实现时,可能要考虑使用DefaultTokenServices
可以插入许多策略来更改访问令牌的格式和存储。默认情况下,它通过随机值创建令牌,并处理除委托给它的令牌的持久性以外的所有内容TokenStore
。默认存储是一个内存中的实现,还有一些其他的实现可用。
其它实现: - InMemoryTokenStore
- JdbcTokenStore
- JwtTokenStore
JWT令牌
要使用JWT令牌,需要在授权服务器中使用JwtTokenStore
。资源服务器还需要能够对令牌进行解码,因此它们JwtTokenStore
依赖JwtAccessTokenConverter
,并且Authorization Server
和Resource Server
都需要相同的实现。令牌是默认签名的,并且资源服务器还必须能够验证签名,因此它需要与授权服务器(共享密钥或对称密钥)相同的对称(签名)密钥,或者它需要公共密钥(验证者密钥)与授权服务器(公私密钥或非对称密钥)中的私钥(签名密钥)相匹配。公共密钥(如果可用)由授权服务器公开/oauth/token_key
端点,默认情况下,访问规则为denyAll()
。你可以通过注入AuthorizationServerSecurityConfigurer
一个标准的SpEL表达式来打开它(例如permitAll()
)。
要使用JwtTokenStore
你的类路径需要spring-security-jwt
。
授权类型
AuthorizationEndpoint
可以通过AuthorizationServerEndpointsConfigurer
配置支持的授权类型。默认情况下,除了密码之外,所有的授权类型都是受支持的(请参阅下面的关于如何打开的细节)。以下属性影响授权类型:
-
authenticationManager
:通过注入密码来开启密码授权AuthenticationManager
。 -
userDetailsService
:如果你注入一个UserDetailsService
或者全局配置(例如GlobalAuthenticationManagerConfigurer
),那么刷新令牌授权将包含对用户详细信息的检查,以确保该帐户仍然是活动的。 -
authorizationCodeServices
:定义了授权代码服务(AuthorizationCodeServices
实例)的身份验证代码授予。。 -
implicitGrantService
:在非法授权期间管理状态。 -
tokenGranter
:完全掌控授予和忽略上面的其他属性
配置端点URL
AuthorizationServerEndpointsConfigurer
有一个pathMapping()
方法。它有两个参数:
- 端点的默认URL路径
- 所需的自定义路径(以"/"开头)
框架提供的URL路径是:
-
/oauth/authorize
:授权端点 -
/oauth/token
:令牌端点 -
/oauth/confirm_access
:用户在此处批准授权 -
/oauth/error
: 用于在授权服务器中渲染错误 -
/oauth/check_token
: 由资源服务器用来解码访问令牌 -
/oauth/token_key
: 如果使用JWT令牌,公开密钥用于令牌验证
注意,授权端点/oauth/authorize
(或其映射替代)应该使用Spring Security
进行保护,以便只有经过认证的用户才能访问。
例如使用标准的Spring Security WebSecurityConfigurer
:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/login").permitAll().and()
// default protection for all resources (including /oauth/authorize)
.authorizeRequests()
.anyRequest().hasRole("USER")
// ... more configuration, e.g. for form login
}
自定义错误实现
授权服务器中的错误处理使用标准的Spring MVC功能,即@ExceptionHandler
端点本身的方法。用户还可以提供WebResponseExceptionTranslator
端点本身,这是改变响应内容的最好方式,而不是渲染的方式。异常委托HttpMesssageConverters
(在MVC配置中可以添加)以及/oauth/error
授权端点的OAuth错误视图。可以自己实现(如只需添加一个@Controller
带@RequestMapping("/oauth/error")
)。
用户角色范围
不仅限于分配给客户端的范围,还要根据用户自己的权限来限制令牌的范围。如果你DefaultOAuth2RequestFactory
在你的系统中使用了AuthorizationEndpoint
一个标志checkUserScopes=true
,你可以设置一个标志来将允许的范围限制在那些与用户角色匹配的范围内。你也可以注入一个OAuth2RequestFactory
,TokenEndpoint
但只有工程(即与密码授予),如果你也安装一个TokenEndpointAuthenticationFilter
, 你只需要在HTTP后面添加该过滤器BasicAuthenticationFilter
。当然,你也可以实现自己的规则,将范围映射到角色并安装你自己的版本OAuth2RequestFactory
。将AuthorizationServerEndpointsConfigurer
让你注入一个定制的OAuth2RequestFactory
,所以你可以使用该功能来建立一个工厂,如果你使用@EnableAuthorizationServer
。
资源服务器配置
资源服务器(可以与授权服务器或单独的应用程序相同)为受OAuth2令牌保护的资源提供服务。Spring OAuth提供了一个实现这种保护的Spring Security认证过滤器。你可以@EnableResourceServer
在一个@Configuration
类上打开它,并根据使用需要,进行配置ResourceServerConfigurer
。以下功能可以配置:
-
tokenServices
:定义令牌服务的bean(实例ResourceServerTokenServices
)。 -
resourceId
:资源的id(可选,但是推荐,并且将由auth服务器验证,如果存在的话)。 - resourecs服务器的其他扩展点(例如,
tokenExtractor
用于从传入请求中提取令牌) - 请求受保护资源的匹配器(默认为全部)
- 受保护资源的访问规则(默认为普通“已认证”)
-
HttpSecurity
Spring Security中配置器所允许的受保护资源的其他自定义。
该@EnableResourceServer
注释将OAuth2AuthenticationProcessingFilter
自动添加到Spring Security过滤器链中。
如果资源服务器和授权服务器在同一个应用程序中,那么不必过多考虑DefaultTokenServices
,因为它实现了所有必需的接口,因此它自动保持一致。如果资源服务器是一个单独的应用程序,那么必须确保匹配授权服务器的功能,并提供一个ResourceServerTokenServices
来知道如何正确解码令牌。与授权服务器一样,可以经常使用DefaultTokenServices
和选择大部分通过TokenStore
(后端存储或本地编码)表示。另一种方法是RemoteTokenServices
这是Spring OAuth功能(不是规范的一部分),允许资源服务器通过授权服务器(/oauth/check_token
)上的HTTP资源来解码令牌。RemoteTokenServices
如果资源服务器中没有大量的流量(每个请求都必须使用授权服务器进行验证),或者您能负担得起缓存结果,那么这种方法非常方便。要使用/oauth/check_token
端点,你需要通过改变它的访问规则(默认为denyAll()
)中暴露它AuthorizationServerSecurityConfigurer
。
如:
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess(
"hasAuthority('ROLE_TRUSTED_CLIENT')");
}
在这个例子中,我们正在配置/oauth/check_token
端点和/oauth/token_key
端点(所以可信资源可以获得JWT验证的公钥)。这两个端点受到使用客户端凭据的HTTP基本身份验证的保护。
OAuth 2.0客户端
OAuth 2.0客户端机制负责访问其他服务器的受OAuth 2.0保护的资源。配置涉及建立用户可能访问的相关受保护资源。客户端可能还需要提供用于存储授权代码和用户访问令牌的机制。
受保护的资源配置
受保护的资源(或“远程资源”)可以定义使用OAuth2ProtectedResourceDetails
类型的bean。受保护的资源具有以下属性:
- id:资源的ID。该id只被客户端用来查找资源; 它从未在OAuth协议中使用过。它也被用作bean的id。
- clientId:OAuth客户端ID。这是OAuth提供商识别您的客户端的ID。
- clientSecret:与资源相关的秘钥。默认情况下为空。
- accessTokenUri:提供访问令牌的提供者OAuth端点的URI。
- scope:逗号分隔的字符串列表,指定对资源的访问范围。默认情况下,不会指定范围。
- clientAuthenticationScheme:您的客户端用来验证访问令牌端点的方案。建议值:“http_basic”和“form”。
不同的授权类型有不同的具体实现OAuth2ProtectedResourceDetails
(例如ClientCredentialsResource
“client_credentials”授权类型)。对于需要用户授权的授权类型,还有一个属性:
-
userAuthorizationUri
:如果用户需要授权访问资源,用户将被重定向到的URI。请注意,这并不是必需的,具体取决于支持哪些OAuth 2配置文件。
客户端配置
对于OAuth 2.0客户端,配置使用简化@EnableOAuth2Client
。这有两件事情:
- 创建一个过滤器bean(
oauth2ClientContextFilter
)来存储当前的请求和上下文。在请求期间需要进行身份验证的情况下,它将管理OAuth身份验证URI中的重定向。 -
AccessTokenRequest
在请求范围内创建一个类型的bean 。这可以被授权代码(或隐式)授权客户端使用,防止与个别用户相关的状态发生冲突。
使用OAuth2RestTemplate
@Autowired
private OAuth2ClientContext oauth2Context;
@Bean
public OAuth2RestTemplate sparklrRestTemplate() {
return new OAuth2RestTemplate(sparklr(), oauth2Context);
}
OAuth2ClientContext
放置在会话范围内,以保持不同用户的状态分离。
访问受保护的资源
一旦你提供了资源的所有配置,你现在可以访问这些资源。用于访问这些资源的建议的方法是通过使用RestTemplate
,只需要提供一个OAuth2ProtectedResourceDetails
。要将其与用户令牌(授权代码授权)结合使用,您应该考虑使用创建一些请求和会话作用域上下文对象的@EnableOAuth2Client
配置(或XML等价物<oauth:rest-template/>
),以便不同用户的请求在运行时不会发生冲突。
一般来说,一个网络应用程序不应该使用密码授权,所以ResourceOwnerPasswordResourceDetails
请避免使用AuthorizationCodeResourceDetails
。如果需要从Java客户端获得密码授权,那么使用相同的机制来配置您OAuth2RestTemplate
的证书并将其添加到AccessTokenRequest
而不是ResourceOwnerPasswordResourceDetails
(所有访问令牌之间共享的)证书。
持久性令牌在客户端
客户端不需要持续令牌,用户在每次重新启动客户端应用程序时都不需要批准新的令牌授予就可以了。ClientTokenServices
接口定义的操作是必要的,为特定用户持续OAuth 2.0令牌。提供了一个JDBC实现,但如果您愿意实现自己的服务来将访问令牌和关联的身份验证实例存储在持久数据库中,则可以这样做。如果你想使用这个功能,你需要提供一个专门配置TokenProvider
的OAuth2RestTemplate
例如:
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2RestOperations restTemplate() {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(accessTokenRequest));
AccessTokenProviderChain provider = new AccessTokenProviderChain(Arrays.asList(new AuthorizationCodeAccessTokenProvider()));
provider.setClientTokenServices(clientTokenServices());
return template;
}