java解析netcore identity4授权token

java对接netcore identity4service 授权,解析token。

获取identity4service 公钥

http://*:5121/.well-known/openid-configuration/jwks

如果identity4service 使用临时加密的方式(AddDeveloperSigningCredentialAddTemporarySigningCredential),会导致identity4service每次重启会生成一对新的证书,所以每次获取公钥要保证是最新的。

也可以给identity4service配置证书。

Startup.cs

1
2
3
4
5
6
7
8
9
10
11
services.AddIdentityServer()
//.AddDeveloperSigningCredential(true, ConstanceHelper.AppSettings.CredentialFileName)
.AddSigningCredential(new X509Certificate2(Path.Combine(basePath,
configuration["Certificates:Path"]),
configuration["Certificates:Password"]))
.AddInMemoryApiResources(Config.GetApis())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryClients(Config.GetClients())
.AddProfileService<ProfileService>()
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
.AddCustomAuthorizeRequestValidator<CustomAuthorizeRequestValidator>();

application.json

1
2
3
4
5
6
{
"Certificates": {
"Path": "Certificates\\IS4.pfx",
"Password": "xxxxxx"
}
}

获取公钥

http://172.16.100.177:5121/.well-known/openid-configuration/jwks

1
{"keys":[{"kty":"RSA","use":"sig","kid":"800740ecb2919cf1bd943da1d7e1c38b","e":"AQAB","n":"wSxc3gNHN7lo9C5LC0Ewoh6aERStezc2HofougTOvfzLgFFWBNBWkCe7X32em1MGzpEguuA90myubLjSvxYvkRq3YJXzwpapAtU32sciXdcPT-d4Qy-RQjQ269pEpLqsSpSYBBC-LHKGTg01AaI_41NS-lw3d_G3DCcT5RaBoMPds5UpOJqHrLLPIKgMGarE7XmPs9w0NyPHz7RU_MHn9UEWTzOByiKBnTZI_nGVEebCGqIdREq8NZnfTjbGrMiRt2i7gY7Cl7K39mwWoovNwvg_p9KscWykiTJzsU2M6EHskRECOfoZ65FHvUHXnZ3IK-VxJ2GqLW_-5eK3lUPY6Q","alg":"RS256"}]}

java 解析验证token

前端获取identity4servicetoken,调用接口;java服务端截取token字符串,获取公钥来做验证。

拦截器代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
private UserAuth userAuth;

@Value("${config.defaultUserId}")
private String defaultUserId;

@Value("${config.umsPublicKey}")
private String umsPublicKey;

@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
/** 如果不是映射到方法直接通过*/
if (!(object instanceof HandlerMethod)) {
return true;
}

/** 验证接口是否需要登录 */
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
/** 判断接口是否需要登录 */
UserToken userToken = method.getAnnotation(UserToken.class);

if (userToken != null) {
String token = httpServletRequest.getHeader("Authorization");

/** 如果token为空 */
if (token == null) {
httpServletResponse.setStatus(401);
throw new DataApiException(HttpStatusEnum.Token401);
}

token = token.replace("Bearer ", "");

DecodedJWT verifier = JWT.decode(token);

/** 验证签名 */
try {
ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor();
ClassPathResource classPathResource = new ClassPathResource(umsPublicKey);
ByteArrayInputStream is = new ByteArrayInputStream(umsPublicKey.getBytes());
JWKSource keySource = new ImmutableJWKSet(JWKSet.load(is));
JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256;
JWSKeySelector keySelector = new JWSVerificationKeySelector(expectedJWSAlg, keySource);
jwtProcessor.setJWSKeySelector(keySelector);
SecurityContext ctx = null;
jwtProcessor.process(token, ctx);
} catch (Exception e) {
throw new DataApiException(HttpStatusEnum.Token401, "token签名验证失败!");
}

Date a = verifier.getExpiresAt();
if (a.getTime() < System.currentTimeMillis()) {
httpServletResponse.setStatus(401);
throw new DataApiException(HttpStatusEnum.Token401, "token时间过期!");
}
String userId = verifier.getSubject();
userAuth.setUserId(userId);
} else {
userAuth.setUserId(defaultUserId);
}
return true;
}
}

InterceptorConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.soyuan.dataapi.interfaces.interceptor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}

UserToken.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.soyuan.dataapi.interfaces.interceptor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})// 可用在方法名上
@Retention(RetentionPolicy.RUNTIME)// 运行时有效
public @interface UserToken {
}

接口使用

controller 使用增加 @UserToken

1
2
3
4
5
6

@GetMapping("/GetApiGroupsByUserId")
@UserToken
public ApiResult<List<ApiGroupDto>> GetApiGroupsByUserId(@RequestParam(required = false) String groupName) {
return ApiResult.ok(apiGroupService.GetApiGroupList(groupName));
}

java解析netcore identity4授权token
https://zhaops-hub.github.io/2021/12/07/java/java解析netcore identity4授权token/
作者
赵培胜
发布于
2021年12月7日
许可协议