IdentityServer4之Clients、Scopes、Claims与Token关联

本文介绍了IdentityServer4中Clients、Scopes、Claims与Token的概念及其相互关系。通过银行的比喻,User代表用户,Client代表应用,Resource代表API资源。Claims表示用户权限,Scopes定义资源范围。详细解析了配置过程,包括User、Client、Resource的配置,并讨论了Scope在模块鉴权中的作用。同时,提到了在实际操作中如何获取Token及无效Scope的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IdentityServer4之Clients、Scopes、Claims与Token关联

参考

官方文档clientidentity_resourceapi_resource:三类配置项介绍描述。

打一个不恰当的比喻来描述一下
User:表示自己 。
Client:表示客户经理,能指引或者代办一些业务。
Resource:表示银行,包括identity_resource(银行基本业务)、api_resource(银行特色业务)。多个resource比作多个分行。

user中的
Claims:自身在银行已经有的业务(包括自己YY的业务)。

client中的
Claims、Scopes是客户经理会推荐给你(User)的业务需不需要看自己。
Claims:好比优惠client可以选择给你或者不给。
Scopes:但是推荐给你的某个Scope业务可能与银行已经下线了但是client不知道。

Resource中的
Claims、Scopes、Scopes->Claims:表示银行的业务。

Token:银行认可自己拥有的业务信息。

User、Client、Resource配置

User配置

new TestUser
{
    SubjectId = "1",
    Username = "ddr",
    Password = "123",
    Claims = new []
    {
        new Claim("name", "ddr"),
        new Claim("get", "get_order"),  //User Claim Type 与 Api Resource中的Claims、Scopes->Claims的Type匹配就会输出到Token
        new Claim("add", "add_order"),
        new Claim("add", "add_account"),
        new Claim("del", "del_all"),
        new Claim("website", "https://ddr.com")
    }
},

 

Client配置

 

 

Identity Resources配置

一般不需要改变就是默认的OpenId、Profile、Email、Phone、Address。

{ IdentityServerConstants.StandardScopes.Profile, 
<think>我们正在讨论基于SpringSecurityOAuth2和JWT实现的授权服务器中`/oauth/token`接口的工作原理。重点包括TokenStore、JwtAccessTokenConverter、AuthorizationServerEndpointsConfigurer等组件的作用及配置方法。根据引用[1][2][3][4][5],我们可以整理出以下关键点:1.**JWT依赖**:需要添加`spring-security-jwt`依赖(引用[1])。2.**JwtAccessTokenConverter**:用于JWT的编码(生成)和解码(解析验证)(引用[2])。在配置中,我们通过`JwtAccessTokenConverter`来设置JWT的签名密钥(引用[3])。3.**TokenStore**:在JWT方案中,我们使用`JwtTokenStore`,它需要一个`JwtAccessTokenConverter`(引用[3])。4.**授权服务器配置**:通过`AuthorizationServerEndpointsConfigurer`来配置TokenStore、TokenEnhancer(即JwtAccessTokenConverter)以及授权模式(如密码模式、客户端凭证模式等)(引用[4])。5.**单点登录(SSO)流程**:用户通过客户端应用登录,客户端应用使用用户名/密码和客户端凭证向授权服务器请求token,授权服务器验证后返回JWT(引用[4][5])。现在,我们将详细解释`/oauth/token`接口的工作逻辑和相关组件。###一、`/oauth/token`接口工作流程当客户端请求`/oauth/token`接口时,授权服务器会执行以下步骤:1.**客户端认证**:首先,客户端需要提供自己的`client_id`和`client_secret`(通常通过HTTPBasic认证或请求参数传递)。授权服务器会验证客户端凭证的有效性。2.**用户认证(授权类型为密码模式时)**:如果客户端请求的是密码模式(`grant_type=password`),则还需要提供用户的用户名和密码。授权服务器会验证用户凭证。3.**令牌生成**:验证通过后,授权服务器生成访问令牌(AccessToken)。在JWT方案中,令牌是一个JWT,包含了令牌的声明(如过期时间、作用域等)以及用户信息。4.**令牌返回**:授权服务器将生成的JWT返回给客户端,客户端可以在后续请求中携带该令牌访问受保护的资源。###二、核心组件作用及配置####1.TokenStore在OAuth2中,`TokenStore`负责令牌的存储和管理。但在使用JWT时,由于JWT是自包含的,不需要存储令牌本身(只需要存储撤销状态,如果需要的话)。我们使用`JwtTokenStore`,它实际上不存储令牌,而是通过JWT来携带信息。配置示例(引用[3]):```java@BeanpublicTokenStoretokenStore(JwtAccessTokenConverterconverter){returnnewJwtTokenStore(converter);}```这里,`JwtTokenStore`需要一个`JwtAccessTokenConverter`来解码和验证JWT。####2.JwtAccessTokenConverter这个组件负责将OAuth2访问令牌(`OAuth2AccessToken`)和认证信息(`OAuth2Authentication`)转换为JWT,以及将JWT解析回`OAuth2AccessToken`和`OAuth2Authentication`(引用[2])。配置示例(引用[3]):```java@BeanpublicJwtAccessTokenConverterjwtTokenEnhancer()throwsIOException{//使用密钥库(JKS文件)来签名JWTKeyStoreKeyFactorykeyStoreKeyFactory=newKeyStoreKeyFactory(newClassPathResource("cnsesan-jwt.jks"),"cnsesan123".toCharArray());JwtAccessTokenConverterconverter=newJwtAccessTokenConverter();converter.setKeyPair(keyStoreKeyFactory.getKeyPair("cnsesan-jwt"));returnconverter;}```也可以使用对称密钥:```java@BeanpublicJwtAccessTokenConverterjwtAccessTokenConverter(){JwtAccessTokenConverterconverter=newJwtAccessTokenConverter();converter.setSigningKey("my-secret-key");//对称密钥returnconverter;}```####3.AuthorizationServerEndpointsConfigurer这是配置授权服务器端点的核心类。我们需要通过它来指定:-`tokenStore`:设置我们配置的`TokenStore`(如`JwtTokenStore`)。-`tokenEnhancer`:设置`JwtAccessTokenConverter`,它实际上是一个`TokenEnhancer`,用于增强令牌(即生成JWT)。-授权模式:支持哪些授权模式(如密码模式、刷新令牌模式等)。配置示例(基于引用[4]):```java@Configuration@EnableAuthorizationServerpublicclassAuthServerConfigextendsAuthorizationServerConfigurerAdapter{@AutowiredprivateAuthenticationManagerauthenticationManager;//用于密码模式@AutowiredprivateTokenStoretokenStore;@AutowiredprivateJwtAccessTokenConverterjwtAccessTokenConverter;@Overridepublicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints){endpoints.authenticationManager(authenticationManager)//密码模式需要.tokenStore(tokenStore).tokenEnhancer(jwtAccessTokenConverter)//设置JWT转换器.allowedTokenEndpointRequestMethods(HttpMethod.POST);}//其他配置(如客户端详情)}```###三、令牌生成细节当`/oauth/token`请求被处理时,`TokenEndpoint`会调用`TokenGranter`来颁发令牌。在密码模式下,`ResourceOwnerPasswordTokenGranter`会被使用。它会:1.使用`AuthenticationManager`验证用户名和密码。2.如果验证成功,则创建`OAuth2Authentication`对象(包含用户信息和客户端信息)。3.调用`AuthorizationServerTokenServices`创建访问令牌。`AuthorizationServerTokenServices`(通常使用`DefaultTokenServices`)会:-使用`TokenEnhancer`(即我们的`JwtAccessTokenConverter`)来生成JWT。-在生成JWT时,它会将`OAuth2AccessToken`的基本信息(如过期时间、作用域)和`OAuth2Authentication`中的用户信息(通过`UserDetails`获取)放入JWT的声明中。###四、JWT的内容生成的JWT包含三个部分:1.**Header**:包含算法(如HS256或RS256)和类型(JWT)。2.**Payload**:包含标准声明(如`exp`过期时间、`sub`主题)和自定义声明(如用户角色、用户名)。3.**Signature**:用于验证令牌的完整性。例如,一个JWT的Payload可能如下:```json{"user_name":"admin","scope":["read","write"],"exp":1670000000,"authorities":["ROLE_ADMIN"],"jti":"a1b2c3d4","client_id":"client1"}```###五、配置总结1.**添加依赖**:`spring-security-oauth2`和`spring-security-jwt`(引用[1])。2.**配置JwtAccessTokenConverter**:设置签名密钥(对称或非对称)(引用[3])。3.**配置TokenStore**:使用`JwtTokenStore`(引用[3])。4.**配置AuthorizationServerEndpoints**:将`TokenStore`和`JwtAccessTokenConverter`设置到`AuthorizationServerEndpointsConfigurer`中,并指定授权模式(引用[4])。###六、注意事项-**令牌存储**:JWT是无状态的,但刷新令牌(refreshtoken)通常需要存储(如使用数据库)。如果需要撤销令牌,也需要存储令牌的标识(jti)和状态。-**密钥安全**:签名密钥必须妥善保管,避免泄露。§§相关问题§§1.如何实现JWT的刷新令牌机制?2.如何自定义JWT中的声明信息?3.在资源服务器中如何配置JWT令牌的验证?4.如何实现令牌撤销(revoke)功能?5.使用JWT作为访问令牌时,如何解决令牌无法即时撤销的问题?</think>### `/oauth/token` 接口工作原理详解(基于 Spring Security OAuth2 + JWT) #### 一、核心组件作用协作流程 ```mermaid sequenceDiagram participant Client as 客户端 participant TokenEndpoint as /oauth/token participant TokenGranter as TokenGranter participant TokenServices as TokenServices participant TokenStore as TokenStore participant JwtConverter as JwtAccessTokenConverter Client->>TokenEndpoint: POST /oauth/token TokenEndpoint->>TokenGranter: grant() TokenGranter->>TokenServices: createAccessToken() TokenServices->>TokenStore: 获取存储策略 TokenServices->>JwtConverter: 调用增强器 JwtConverter->>TokenServices: 返回JWT令牌 TokenServices-->>TokenGranter: OAuth2AccessToken TokenGranter-->>TokenEndpoint: 令牌响应 TokenEndpoint-->>Client: JSON响应(JWT) ``` #### 二、关键组件详解 1. **`TokenStore` (令牌存储)** - **作用**:管理令牌的存储、读取和删除 - **JWT 实现**:`JwtTokenStore`(引用[3]) ```java @Bean public TokenStore tokenStore(JwtAccessTokenConverter converter) { return new JwtTokenStore(converter); // 无状态存储 } ``` - **特点**:JWT 方案中无需持久化令牌,但需存储刷新令牌 2. **`JwtAccessTokenConverter` (JWT 处理器)** - **核心功能**(引用[2]): - `encode()`:将 `OAuth2AccessToken` + `OAuth2Authentication` → JWT - `decode()`:解析 JWT → `OAuth2AccessToken` - **配置示例**(引用[3]): ```java @Bean public JwtAccessTokenConverter jwtTokenEnhancer() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // 对称密钥方案 converter.setSigningKey("my-secret-key"); // 非对称密钥方案 KeyStoreKeyFactory factory = new KeyStoreKeyFactory( new ClassPathResource("keystore.jks"), "password".toCharArray()); converter.setKeyPair(factory.getKeyPair("alias")); return converter; } ``` 3. **`AuthorizationServerEndpointsConfigurer` (端点配置器)** - **核心配置**: ```java @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints .tokenStore(tokenStore) // 绑定TokenStore .tokenEnhancer(jwtAccessTokenConverter) // 绑定JWT处理器 .authenticationManager(authenticationManager) // 密码模式必需 .allowedTokenEndpointRequestMethods(HttpMethod.POST); } ``` - **关键作用**: - 关联令牌生成组件链 - 定义支持的授权模式(密码模式/客户端凭证等) - 配置令牌增强器链(可多个增强器组合) #### 三、`/oauth/token` 请求处理流程 1. **请求验证阶段**: - 客户端身份验证(HTTP Basic 或参数) - 授权类型验证(如 `grant_type=password`) - 用户凭证验证(密码模式需 `username`/`password`) 2. **令牌生成阶段**: ```java // 伪代码:TokenServices 创建令牌 public OAuth2AccessToken createAccessToken(OAuth2Authentication auth) { // 1. 检查现有令牌是否有效 OAuth2AccessToken existingToken = tokenStore.getAccessToken(auth); if (existingToken != null && !existingToken.isExpired()) { return existingToken; } // 2. 创建新令牌(核心步骤) DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString()); token.setExpiration(calculateExpiry()); token.setScope(auth.getOAuth2Request().getScope()); // 3. JWT增强处理(添加自定义声明等) token = jwtAccessTokenConverter.enhance(token, auth); // 4. 存储令牌(JWT模式下只存储刷新令牌) tokenStore.storeAccessToken(token, auth); return token; } ``` 3. **JWT 生成细节**: - **标准声明**:`sub`(用户名), `exp`(过期时间), `jti`(令牌ID), `client_id`, `scope` - **自定义声明**(扩展用户信息): ```java public class CustomTokenEnhancer extends JwtAccessTokenConverter { @Override protected Map<String, Object> encode(OAuth2Authentication auth) { Map<String, Object> claims = super.encode(auth); // 添加自定义声明 claims.put("department", ((User)auth.getPrincipal()).getDepartment()); return claims; } } ``` #### 四、典型配置全流程(SSO 单点登录示例) 1. **依赖配置**(引用[1][3]): ```xml <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> ``` 2. **授权服务器配置**(引用[4][5]): ```java @Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired AuthenticationManager authenticationManager; @Autowired TokenStore tokenStore; @Autowired JwtAccessTokenConverter jwtConverter; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client1") .secret("{noop}secret1") .scopes("read") .authorizedGrantTypes("password", "refresh_token"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints .tokenStore(tokenStore) .tokenEnhancer(jwtConverter) .authenticationManager(authenticationManager); } } ``` 3. **资源服务器验证流程**: - 客户端携带 JWT 访问资源 - 资源服务器用相同密钥验证签名 - 解析 JWT 获取用户身份和权限 #### 五、常见问题解决方案 1. **令牌自定义问题** - **方案**:组合使用 `TokenEnhancer` 链 ```java endpoints.tokenEnhancer(tokenEnhancerChain()); private TokenEnhancer tokenEnhancerChain() { List<TokenEnhancer> enhancers = new ArrayList<>(); enhancers.add(new CustomTokenEnhancer()); // 自定义增强器 enhancers.add(jwtAccessTokenConverter); // JWT转换器 return new TokenEnhancerChain(enhancers); } ``` 2. **刷新令牌机制** - JWT 访问令牌过期后,使用刷新令牌获取新令牌 - 刷新令牌需要持久化存储(引用[3]): ```java @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); // 刷新令牌存数据库 } ``` 3. **安全加固建议** - 使用非对称加密(RSA)替代对称加密 - 设置合理的令牌有效期: ```java DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setAccessTokenValiditySeconds(3600); // 1小时 tokenServices.setRefreshTokenValiditySeconds(2592000); // 30天 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值