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.
相关产品推荐
相关产品推荐

