You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak中基于移动端应用的自定义无密码认证实现求助

Keycloak集成自定义移动端无密码认证:同步应用响应到认证流程

需求概述

我们要实现一套基于自有移动端应用的无密码认证流程,步骤如下:

  • 用户输入用户名
  • 跳转至密码页面后,点击「尝试其他方式」
  • 选择「通过移动端应用登录」选项
  • 移动端收到登录请求通知
  • 用户在应用内批准/拒绝请求
  • 批准则完成登录,拒绝则重启流程

当前进展

已完成两个核心组件:

  • 自定义认证器:负责向移动端发送登录请求通知
  • 自定义领域资源:负责接收移动端传回的用户批准/拒绝响应

核心问题

自定义领域资源能收到响应,但没法把结果同步回Keycloak的认证流程,不清楚该用什么机制中断或继续认证流程。

解决方案步骤

1. 用认证会话关联请求与状态

在自定义认证器的authenticate方法中,生成唯一的请求ID(比如UUID),将ID存储到当前认证会话的notes中,同时把ID传给移动端应用:

@Override
public void authenticate(AuthenticationFlowContext context) {
    String requestId = UUID.randomUUID().toString();
    // 把请求ID存入认证会话
    context.getAuthenticationSession().setAuthNote("mobile-auth-request-id", requestId);
    // 调用通知服务向移动端发送请求,携带requestId
    mobileNotificationService.sendLoginRequest(context.getUser(), requestId);
    // 返回挑战,引导前端进入等待状态(比如显示"等待移动端确认"页面)
    context.challenge(Response.ok().entity("Waiting for mobile app confirmation").build());
}

2. 自定义领域资源更新会话状态

在接收移动端响应的自定义资源中,通过请求ID找到对应的认证会话,更新会话的状态标记:

@Path("/mobile-auth-response")
public class MobileAuthResource {
    private final KeycloakSession session;

    public MobileAuthResource(KeycloakSession session) {
        this.session = session;
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response handleResponse(MobileAuthResponse response) {
        // 根据requestId查找认证会话
        AuthenticationSessionManager sessionManager = session.getProvider(AuthenticationSessionManager.class);
        AuthenticationSession authSession = sessionManager.findAuthenticationSessionByAuthNote(
            session.getContext().getRealm(), 
            "mobile-auth-request-id", 
            response.getRequestId()
        );

        if (authSession == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        // 更新会话状态:approved/rejected
        authSession.setAuthNote("mobile-auth-status", response.isApproved() ? "approved" : "rejected");
        return Response.ok().build();
    }
}

3. 让认证器轮询检查会话状态

自定义认证器需要在每次请求时检查会话的状态标记,决定继续或终止流程:

@Override
public void authenticate(AuthenticationFlowContext context) {
    String status = context.getAuthenticationSession().getAuthNote("mobile-auth-status");
    if (status == null) {
        // 状态未更新,继续等待,返回挑战
        context.challenge(Response.ok().entity("Waiting for mobile app confirmation").build());
    } else if ("approved".equals(status)) {
        // 用户批准,标记认证成功,继续流程
        context.success();
    } else {
        // 用户拒绝,清除会话状态,重启流程
        context.getAuthenticationSession().removeAuthNote("mobile-auth-request-id");
        context.getAuthenticationSession().removeAuthNote("mobile-auth-status");
        context.failure(AuthenticationFlowError.INVALID_CREDENTIALS);
    }
}

4. 前端配合轮询

前端在收到挑战后,每隔几秒向Keycloak的认证端点(比如/auth/realms/{realm}/protocol/openid-connect/auth)发起请求,触发认证器检查状态。一旦状态更新,Keycloak会自动跳转完成登录或返回错误。

关键注意事项

  • 设置合理的认证会话超时时间:在Keycloak控制台的「领域设置」→「会话」中调整,避免用户未及时操作导致会话失效。
  • 确保请求ID的唯一性:用UUID足够保证,避免不同请求之间的冲突。
  • 安全校验:自定义领域资源要验证请求的合法性(比如移动端的签名、用户身份匹配),防止恶意请求篡改状态。

内容的提问来源于stack exchange,提问作者Syed M. SM.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:26:07