keycloak10.0.1安装教程
具体开发参考:https://blog.csdn.net/m0_46267097/article/details/106092404
注意:依赖包的scope需要是provided
<dependency>
<groupId>org.keycloakgroupId>
<artifactId>keycloak-servicesartifactId>
<version>10.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.keycloakgroupId>
<artifactId>keycloak-coreartifactId>
<version>10.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.keycloakgroupId>
<artifactId>keycloak-server-spiartifactId>
<version>10.0.1version>
<scope>providedscope>
dependency>
需要去掉上面引用的几个keycloak的jar包,不然启动keycloak会无限报错!!!
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.5.1version>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId> maven-assembly-plugin artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependenciesdescriptorRef>
descriptorRefs>
<archive>
<manifest>
<mainClass>mainClass>
manifest>
<addMavenDescriptor>falseaddMavenDescriptor>
archive>
configuration>
<executions>
<execution>
<id>make-assemblyid>
<phase>packagephase>
<goals>
<goal>singlegoal>
goals>
execution>
executions>
plugin>
plugins>
<finalName>keycloak-spifinalName>
build>
在resources目录下添加services文件夹,在services文件夹下新建文件,文件名为具体实现的工厂接口的名称,比如我这里实现的是UserStorageProviderFactory工厂,就新建一个文件名为UserStorageProviderFactory。文件内容为具体实现类的全限定名。
org.keycloak.examples.federation.properties.MyUserStorageProviderFactory
package org.keycloak.examples.federation.properties;
import org.keycloak.component.ComponentModel;
import org.keycloak.credential.CredentialInput;
import org.keycloak.credential.CredentialInputValidator;
import org.keycloak.credential.CredentialModel;
import org.keycloak.models.*;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.adapter.AbstractUserAdapter;
import org.keycloak.storage.user.UserLookupProvider;
import java.util.*;
/**
* MyUserStorageProvider
*
* @return
* @exception
* @author : cy
* @date : 2020/5/14
*/
public class MyUserStorageProvider implements UserStorageProvider,UserLookupProvider, CredentialInputValidator{
protected KeycloakSession session;
protected Properties properties;
protected ComponentModel model;
/** map of loaded users in this transaction */
protected Map<String,UserModel> loadedUsers = new HashMap<>();
public MyUserStorageProvider(KeycloakSession session, ComponentModel model, Properties properties) {
this.session = session;
this.model = model;
this.properties = properties;
}
/**
* 创建用户模型
*/
protected UserModel createAdapter(RealmModel realm, String username) {
return new AbstractUserAdapter(session, realm, model) {
@Override
public String getUsername() {
return username;
}
};
}
/**
* 通过用户名查血用户
*/
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
UserModel adapter = loadedUsers.get(username);
if (adapter == null) {
String password = properties.getProperty(username);
if (password != null) {
adapter = createAdapter(realm, username);
loadedUsers.put(username, adapter);
}
}
return adapter;
}
/**
* 通过用户ID查血用户
*/
@Override
public UserModel getUserById(String id, RealmModel realm) {
StorageId storageId = new StorageId(id);
String username = storageId.getExternalId();
return getUserByUsername(username, realm);
}
/**
* 通过邮箱查血用户
*/
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return null;
}
@Override
public void close() {
}
/**
* 运行时将调用该方法,以确定是否为用户配置了特定的凭据类型。此方法检查是否已为用户设置了密码
*/
@Override
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
String password = properties.getProperty(user.getUsername());
return credentialType.equals(CredentialModel.PASSWORD) && password != null;
}
@Override
public boolean supportsCredentialType(String credentialType) {
return credentialType.equals(CredentialModel.PASSWORD);
}
/**
* 方法负责验证密码。
* 该CredentialInput参数实际上只是所有凭证类型的抽象接口。
* 我们确保我们支持凭证类型,并且它也是的实例UserCredentialModel。
* 当用户通过登录页面登录时,密码输入的纯文本将放入的实例UserCredentialModel。
* 该isValid()方法根据存储在属性文件中的纯文本密码检查此值。返回值true表示密码有效。
*/
@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
if (!supportsCredentialType(input.getType())) {
return false;
}
String password = properties.getProperty(user.getUsername());
if (password == null) {
return false;
}
return password.equals(input.getChallengeResponse());
}
}
package org.keycloak.examples.federation.properties;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.storage.UserStorageProviderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* MyUserStorageProviderFactory
*
* @return
* @exception
* @author : cy
* @date : 2020/5/14
*/
public class MyUserStorageProviderFactory
implements UserStorageProviderFactory<MyUserStorageProvider> {
public static final String PROVIDER_NAME = "my-user";
@Override
public String getId() {
return PROVIDER_NAME;
}
private static final Logger logger = Logger.getLogger(MyUserStorageProviderFactory.class);
protected Properties properties = new Properties();
@Override
public void init(Config.Scope config) {
/**
* 我们可以指定用户属性文件的类路径,而不是对其进行硬编码。然后,您可以在中检索配置
*/
String path = config.get("path");
InputStream is = getClass().getClassLoader().getResourceAsStream(path);
if (is == null) {
logger.warn("Could not find users.properties in classpath");
} else {
try {
properties.load(is);
} catch (IOException ex) {
logger.error("Failed to load users.properties file", ex);
}
}
}
@Override
public MyUserStorageProvider create(KeycloakSession session, ComponentModel model) {
return new MyUserStorageProvider(session, model, properties);
}
}
使用上述maven-compiler-plugin的打包插件打包后,把jar包手动放置到keycloak-10.0.1\standalone\deployments目录下。
修改keycloak-10.0.1\standalone\configuration\standalone.xml,添加如下配置,其中path位置输入的是自定义properties配置文件路径。
<spi name="storage">
<provider name="readonly-property-file" enabled="true">
<properties>
<property name="path" value="/other-users.properties"/>
properties>
provider>
spi>
properties文件内容如下
admin=123456
运行keycloak-10.0.1\bin\standalone.bat启动项目,登录进入Admin Console
左侧菜单栏选择User Federation后点击右侧下拉框,可以看见我们加入的Provider出现了。
选择后进入其配置页面
通过这种方法获得的用户角色名为offline_access,有了角色名,也有了数据来源,后期我们的用户验证就可以开始为所欲为喽。
具体开发参考Client开发,或者再来个链接:SpringBoot集成Keycloak简单实例
不过其中配置需要稍稍修改一下,需要把原来的authRoles里面的角色改成offline_access,一定要改,不然你会发现登了半天进去的永远是报错页面。
直接贴全配置:
spring:
application:
name: keycloakDemo
server:
port: 8600
keycloak:
# 表示是一个public的client
public-client: true
# keycloak的地址
auth-server-url: http://localhost:8080/auth
# keycloak中的realm
realm: myrealm
# client ID
resource: keycloakDemo
# 安全约束
securityConstraints:
- authRoles:
# 以下路径需要demoUser角色才能访问
- offline_access
securityCollections:
# name可以随便写
- name: common user
patterns:
- /demo/getValue
输入测试地址http://localhost:8600/demo/getValue
输入配置文件中的用户名、密码后点击登录按钮,成功。
开发参考链接:官网SPI开发文档