技术标签: 开发实例
具体开发参考:https://blog.csdn.net/m0_46267097/article/details/106092404
注意:依赖包的scope需要是provided
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<version>10.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>10.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>10.0.1</version>
<scope>provided</scope>
</dependency>
需要去掉上面引用的几个keycloak的jar包,不然启动keycloak会无限报错!!!
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId> maven-assembly-plugin </artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass></mainClass>
</manifest>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<finalName>keycloak-spi</finalName>
</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>
<!-- 这里配置的是工厂模式中加载的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开发文档
文章浏览阅读66次。Sample Probability SpaceA simple probability space consist of a tuple (Ω\OmegaΩ,ε\varepsilonε,p)Ω\OmegaΩ is a finite set (with cardinality k= ∣\mid∣Ω\OmegaΩ∣\mid∣)ε\varepsilonε = { A : A ⊆\subseteq⊆ Ω\OmegaΩ } consist of all finite subsetsEach events _probability space例题
文章浏览阅读348次。由于早先写的WeiboCrawler问题很多,而且当时我有提到,其实可以实现一个通用的爬虫框架。最近由于要抓取新的数据,于是我就写了这个cola。下面的文字来自wiki。Cola是一个分布式的爬虫框架,用户只需编写几个特定的函数,而无需关注分布式运行的细节。任务会自动分配到多台机器上,整个过程对用户是透明的。依赖由于Cola配置文件使用的yaml,所以Cola只依赖于pyyaml,安装easy_i..._cola爬虫
文章浏览阅读75次。在这个买车已经不是什么难事的年代,大多数人出行都会选择自驾方式,但自驾出游必然要面临一系列的问题以及做足准备工作。名悦集团小编给大家总结出了这次国庆假期出行自驾游攻略,为了保证自驾过程的安全顺利,玩得更加痛快,临行前的车辆检查时必不可少的,这些项目可以自己检查,如果实在是懒或者不懂,可以在临行前去4S店做个基础保养,以让爱车在最佳车况陪伴自己和家人朋友开始这段愉快的旅程。1.轮胎轮胎的检查是自驾前需要关键的检查之一,在自驾的旅程上不管是轮胎没气还是爆胎,都是非常令人揪心的,如果是在高速或者...
文章浏览阅读3.6k次,点赞3次,收藏7次。参考文档 https://blog.csdn.net/huangyabin001/article/details/28434989https://blog.csdn.net/huangyabin001/article/details/28435093#commentshttps://blog.csdn.net/jieqiong1/article/details/712629871..._android 输入法源码
本文介绍了如何在Ubuntu下使用nnUNet训练自己的数据集,不涉及原理解析,只提供实现步骤。包括nnUNet简介、修改训练参数和文件位置等操作。详细内容可参考Tina的博文。
文章浏览阅读9.9k次,点赞10次,收藏88次。对于抢购系统来说,首先要有可抢购的活动,而且这些活动具有促销性质,这种大型活动的负载可能是平时的几十倍,所以通过增加硬件、优化瓶颈代码等手段是很难达到目标的,所以抢购系统得专门设计。在这里我们说的库存不是真正意义上的库存,其实是该促销可以抢购的数量,真正的库存在基础库存服务。用户点击『提交订单』按钮后,在抢购系统中获取了资格后才去基础库存服务中扣减真正的库存;而抢购系统控制的就是资格/剩余数。传统方案利用数据库行锁,但是在促销高峰数据库压力过大导致服务不可用,目前采用redis集群(16分片)缓存促销信息,
文章浏览阅读2.8w次,点赞10次,收藏9次。用正则表达式匹配两个字符中间的文本String skh ="(?<=\\《)[^\\》]+";//用于匹配《》里面的文本String str="但实际上《kajdwdej》孙大伟多";//测试字符串Pattern pattern=Pattern.compile(skh); Matcher matcher=pattern.matcher(str); boolean is=matche_正则表达式 匹配多个括号
文章浏览阅读553次。之前一直看项目用过这个东西,但是自己都不怎么熟悉,大概就知道可以画一些圆角之类的~ 今天就来好好了解一下吧~Shape里面有很多属性,依次学习一下第一步~首先来写一个Button这个布局文件就不贴了...太简单了~ (PS:说贴出来的站出来,我保证不打死你!)接下来开始学习第一个属性:Solid:(填充)在Drawable里面创建一个butt_linear radial sweep分别代表的什么
文章浏览阅读6.1k次。上图是Sci文献中的dose–response curves (剂量反应曲线),横坐标是药物GS-Se-SG浓度的对数值,纵坐标是Rrelative cell viability(相对细胞活性,% of control),从图注中可以知道IC50为5.1 μM。那么什么是IC50呢?IC50 (half maximal inhibitory concentration)是指被测量的拮抗剂的半抑制浓..._graphpad细胞增殖曲线
文章浏览阅读658次。二叉查找树(含递归、非递归遍历)_二叉排序树非递归查找
文章浏览阅读3.1k次。spark-sql> select * from zps_d001 limit 1;Error in query: org.apache.hadoop.hive.ql.metadata.HiveException: Unable to fetch table zps_xxx. Invalid method name: 'get_table_req'org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.H_invalid method name: 'get_table_req
文章浏览阅读1.7w次。我这边使用得是vue+elementvue得状态组成actions 这个是异步请求 通过异步请求得话 然后在调用 mutations.jsmutations.js 将数据提交到这里 this.$commit(‘test’,testTemp)index.js 这个是将数据初始化getters 这个是将 this.$store.getters.test 就能获取到了 testTemp写法是这个写法最后得原因是因为我这在 index.js 和mutation.js 为定义常量##_unknown mutation type