具体流程如下
生成keystore.jks文件
- 登录keycloak,进入管理控制台->clients 菜单

- 点击右上创建client
客户端协议选择 openid-connect
- 保存后,设置客户端协议为:credential

有效的重定向URI可随意输入,如:https://github.com/ 保存后,即可选择凭据标签页
客户端认证器选择:Signed Jwt,点击生成新密钥和证书,进入如下界面
点击生成和下载,将下载的keystore.jks文件保存
如果觉得上述步骤过于繁琐,可直接借用keycloak自带的client:account,生成keystore.jks
生成keystore.jks文件后,再修改回来
上传keystore.jks文件到服务器并添加密钥链
1.将生成的keystore.jks文件上传到keycloak服务器,并拷贝路径
linux服务器可通过yum 安装 lrzsz插件,yum install -y lrzsz,通过命令rz -bye上传
2.添加密钥链
选择 Realm Settings -> Keys -> Providers,点击右上角下拉框,新增java-keystore,在跳转页面输入Keystore(keystore.jks存放路径)、Keystore Password、Key Alias、Key Password保存

保存后,
可复制kid,在页面http://localhost:8080/auth/realms/demo/protocol/openid-connect/certs验证是否生效
外部应用生成jwt token
maven添加必要的依赖
以后代码供参考
BaseAccessToken.java
@SuperBuilder
public abstract class BaseAccessToken {
@JsonProperty("exp")
private long expiration;
@JsonProperty("aud")
@Singular
private Set<String> audiences;
@JsonProperty("iss")
private String issuer;
@JsonProperty("roles")
@Singular
private Set<String> roles;
@JsonProperty("scope")
private String scope;
}
KeycloakJwtProperties.java
@Getter
@Setter
public class KeycloakJwtProperties {
private boolean enabled = false;
private String clientKeystoreFile;
private String clientKeystorePassword;
private String clientKeyPassword;
private String clientKeyAlias;
}
KeyPairUtil.java
@Getter
private KeyPair keyPair;
public KeyPairUtil(KeycloakJwtProperties properties) {
loadKeystore(properties);
}
private void loadKeystore(KeycloakJwtProperties properties) {
keyPair = KeystoreUtil.loadKeyPairFromKeystore(properties.getClientKeystoreFile(), properties.getClientKeystorePassword(), properties.getClientKeyPassword(), properties.getClientKeyAlias(), KeystoreUtil.KeystoreFormat.JKS);
}
}
KeycloakSignedJwtAutoConfiguration.java
@ConditionalOnProperty("jwt.enabled")
@EnableConfigurationProperties({KeycloakJwtProperties.class})
public class KeycloakSignedJwtAutoConfiguration {
private final KeycloakJwtProperties keycloakJwtProperties;
public KeycloakSignedJwtAutoConfiguration(KeycloakJwtProperties keycloakJwtProperties) {
this.keycloakJwtProperties = keycloakJwtProperties;
}
@Bean
public KeyPairUtil keyPairUtil(){
return new KeyPairUtil(keycloakJwtProperties);
}
}
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.oauth2.config.KeycloakSignedJwtAutoConfiguration
项目发布到nexus私有仓库,其他spring boot项目导入依赖、增加配置后,通过下面代码生成自定义token
application.yml
security:
oauth2:
client:
provider:
oidc:
issuer-uri: http://cas.xxx.net/auth/realms/demo
jwt:
enabled: true
client-keystore-file: /Users/jj/Documents/workspaces/Refactor/ops/src/main/resources/keystore.jks
client-keystore-password: 123456
client-key-password: 123456
client-key-alias: demo-client
public class StartRunner implements CommandLineRunner {
private final Logger logger = LoggerFactory.getLogger(StartRunner.class);
private final KeyPairUtil keyPairUtil;
public StartRunner(KeyPairUtil keyPairUtil) {
this.keyPairUtil = keyPairUtil;
}
@Override
public void run(String... args) throws Exception {
testCustomToken();
}
private void testCustomToken() throws Exception {
DeviceAccessToken deviceAccessToken = DeviceAccessToken.builder()
.expiration(Instant.now().plus(1, ChronoUnit.DAYS).getEpochSecond())
.issuer("http://cas.xxx.net/auth/realms/demo")
.audience("device")
.role("ROLE_DEVICE")
.role("ROLE_ADMIN")
.scope("device")
.deviceId(111L)
.serialNumber("20720D39021C")
.hospitalId(222L)
.commonDeptId(333L)
.customDeptId(444L)
.customDeptName("自建科室")
.locationId(555L)
.locationName("1床")
.provinceId(666L)
.cityId(777L)
.deviceType(DeviceType.TABLET.toString()).build();
String token = new JWSBuilder().jsonContent(deviceAccessToken).rsa256(keyPairUtil.getKeyPair().getPrivate());
logger.debug("token: {}", token);
}
}
客户端通过上述步骤生成token访问受保护的资源时,会遍历cert做token的有效性认证,这样keycloak只需要提供公钥供app应用做token的有效性验证,token的生成和使用由app自身控制