keycloak~自定义注册流程
添加register.ftl皮肤
- resources/iframe/login/register.ftl
- resources/iframe/login/resources 这里定义静态文件
注册的FormAction
后面需要在keycloak管理后台添加它
package org.keycloak.phone.authentication.forms;
/**
* 注册流程.
*/
public class RegistrationNew implements FormActionFactory, FormAction {
public static final String PROVIDER_ID = "new-registration";
private static AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.DISABLED};
List<FormMessage> errors = new ArrayList<>();
private KeycloakSession session;
public static String getClientId(FormContext context) {
if (context.getHttpRequest().getUri().getQueryParameters().containsKey("client_id")) {
return context.getHttpRequest().getUri().getQueryParameters().getFirst("client_id");
}
return null;
}
@Override
public String getDisplayType() {
return "New Registration Form";
}
@Override
public String getReferenceCategory() {
return null;
}
@Override
public boolean isConfigurable() {
return false;
}
@Override
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
return REQUIREMENT_CHOICES;
}
@Override
public boolean isUserSetupAllowed() {
return false;
}
@Override
public String getHelpText() {
return "New Registration";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return null;
}
@Override
public FormAction create(KeycloakSession session) {
return this;
}
@Override
public void init(Config.Scope config) {
}
// FormAction
@Override
public void postInit(KeycloakSessionFactory factory) {
session = factory.create();
}
@Override
public void close() {
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public void buildPage(FormContext formContext, LoginFormsProvider loginFormsProvider) {
System.out.println(session.getContext().getUri().getQueryParameters().getFirst("username"));
loginFormsProvider.setAttribute("username",
session.getContext().getUri().getQueryParameters().getFirst("username"));
loginFormsProvider.createForm("register.ftl");
}
@Override
public void validate(ValidationContext context) {
// context.getSession().setAttribute("realm", context.getRealm());
System.out.println("注册用户,验证表单");
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
String loginType = formData.getFirst("loginType");
String phoneNumber = formData.getFirst("phoneNumber");
String email = formData.getFirst("email");
String username = formData.getFirst("username");
String locale = Optional.ofNullable(formData.getFirst("kc_locale")).orElse("zh-CN");
String smsCode;
if (loginType.equals(LoginType.phone.name())) {
smsCode = formData.getFirst(SMS_CODE);
TokenCodeServiceProvider tokenCodeServiceProvider =
context.getSession().getProvider(TokenCodeServiceProvider.class);
tokenCodeServiceProvider.validateCode(null, phoneNumber, smsCode);
} else {
smsCode = formData.getFirst("emailCode");
EmailCodeServiceProvider tokenCodeServiceProvider =
context.getSession().getProvider(EmailCodeServiceProvider.class);
tokenCodeServiceProvider.validateCode(null, email, smsCode);
}
if (findUserByUsername(context.getSession().users(), context.getRealm(), username) != null) {
context.error(Errors.INVALID_REGISTRATION);
errors.add(new FormMessage(RegistrationPhoneNumber.FIELD_PHONE_NUMBER,
getMessageFromResource(session, locale, "usernameExists")));
context.validationError(formData, errors);
return;
}
if (loginType.equals("phone") && phoneIsExist(session, phoneNumber)) {
context.error(Errors.INVALID_REGISTRATION);
errors.add(new FormMessage(RegistrationPhoneNumber.FIELD_PHONE_NUMBER,
getMessageFromResource(session, locale, "phoneNumberExists")));
context.validationError(formData, errors);
return;
}
context.success();
}
@Override
public void success(FormContext formContext) {
MultivaluedMap<String, String> formData = formContext.getHttpRequest().getDecodedFormParameters();
String loginType = formData.getFirst("loginType");
String email = formData.getFirst("email");
String phoneNumber = formData.getFirst("phoneNumber");
String username = formData.getFirst("username");
formContext.getEvent().detail(Details.USERNAME, username)
.detail(Details.REGISTER_METHOD, "form");
KeycloakSession session = formContext.getSession();
UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class);
UserProfile profile = profileProvider.create(UserProfileContext.REGISTRATION_USER_CREATION, formData);
UserModel user = profile.create();
user.setEnabled(true);
if (loginType.equals(LoginType.phone.name())) {
user.setSingleAttribute(KeycloakUtil.PHONE, phoneNumber);
user.setSingleAttribute(KeycloakUtil.PHONE_VERIFIED, "true");
formContext.getEvent().detail(KeycloakUtil.PHONE, phoneNumber);
}
if (loginType.equals(LoginType.email.name())) {
if (!KeycloakUtil.REQUIRED_EMAIL_SUFFIX.contains(KeycloakUtil.getEmailSuffix(email))) {
user.setEnabled(false);
user.setEmail(email);
user.setEmailVerified(true);
formContext.getEvent().detail("Email", email);
}
}
formContext.setUser(user);
formContext.getAuthenticationSession().setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
formContext.getEvent().user(user);
formContext.getEvent().success();
formContext.newEvent().event(EventType.LOGIN);
formContext.getEvent().client(formContext.getAuthenticationSession().getClient().getClientId())
.detail(Details.REDIRECT_URI, formContext.getAuthenticationSession().getRedirectUri())
.detail(Details.AUTH_METHOD, formContext.getAuthenticationSession().getProtocol());
String authType = formContext.getAuthenticationSession().getAuthNote(Details.AUTH_TYPE);
if (authType != null) {
formContext.getEvent().detail(Details.AUTH_TYPE, authType);
}
}
@Override
public boolean requiresUser() {
return false;
}
@Override
public boolean configuredFor(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) {
return true;
}
@Override
public void setRequiredActions(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) {
}
}
注册流程核心方法说明
- 注意:注册用户成功后,会自动登录,并重写向到来源页面
- buildPage方法:渲染页面
- validate方法:表单验证
- success方法:提交表单,如果这里要访问context,realms等上下文,需要由validate方法通过 context.getSession().setAttribute()方法进行数据传递
注册这个Form Action
- resources/META-INF/services/org.keycloak.authentication.FormActionFactory
keycloak后台配置新的注册程序
合集:
keycloak
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
2022-07-29 java~ForkJoinPool分而致之处理大数据
2022-07-29 java~Map集合整理
2020-07-29 springcloud~微服务里的oauth2集成总结
2015-07-29 我心中的核心组件(可插拔的AOP)~分布式Session组件
2012-07-29 不说技术~有时,开发者还是应该讲究一点!
2011-07-29 面向对象~程序应该具有可维护性,代码可复用性,可扩展性和灵活性