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后台配置新的注册程序

posted @   张占岭  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享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 面向对象~程序应该具有可维护性,代码可复用性,可扩展性和灵活性
点击右上角即可分享
微信分享提示