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

基于Keycloak的受限登录功能实现问询:无密码认证难题

Great question! Let's walk through how to implement your restricted-access login system, focusing on solving the passwordless authentication gap in Keycloak.

整体流程梳理

First, let's recap your existing design to make sure we're aligned:

  • Validate that the login request comes from a trusted source
  • Generate a unique, secure hash code tied to the user/request
  • Send an email to the user containing a login link with this hash code
  • When the user clicks the link, your controller verifies the hash code's validity
  • Unresolved piece: Create the user in Keycloak and authenticate them without requiring a password
Keycloak Passwordless Authentication Solutions

Here are three practical approaches to solve the passwordless step, ordered by simplicity and adherence to Keycloak's built-in features:

Approach 1: Use Keycloak's Built-in Action Tokens

Keycloak has a native mechanism for one-time login tokens (LOGIN_TOKEN) that lets users authenticate without a password. Here's how to implement it:

  1. Create the user in Keycloak (if they don't exist)
    Use the Keycloak Admin Client to create the user programmatically. Example Java code:

    // Initialize Keycloak Admin Client (configure with your realm/client details)
    Keycloak keycloak = KeycloakBuilder.builder()
        .serverUrl("https://your-keycloak-instance/auth")
        .realm("your-realm")
        .clientId("admin-cli")
        .username("admin-user")
        .password("admin-password")
        .build();
    
    // Define user details
    UserRepresentation user = new UserRepresentation();
    user.setUsername("user@example.com");
    user.setEmail("user@example.com");
    user.setEnabled(true);
    
    // Create user and fetch their ID
    Response createUserResponse = keycloak.realm("your-realm").users().create(user);
    String userId = createUserResponse.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");
    
  2. Generate a one-time login token
    Create a LOGIN_TOKEN which grants temporary access to authenticate the user:

    // Token expires in 1 hour (adjust as needed)
    long expiration = System.currentTimeMillis() + 3600000;
    ActionTokenActionToken loginToken = new ActionTokenActionToken(
        userId,
        ActionTokenActionToken.LOGIN_TOKEN,
        expiration,
        null // No additional notes needed
    );
    // Set the redirect URL where the user lands after login
    loginToken.setRedirectUri("https://your-app.com/post-login");
    
    // Encode the token using Keycloak's token service
    String encodedToken = keycloak.realm("your-realm").tokens().encode(loginToken);
    
  3. Redirect the user to Keycloak's login endpoint
    Construct the login URL with the encoded token and send the user there:

    https://your-keycloak-instance/auth/realms/your-realm/login-actions/action-token?key=${encodedToken}
    

    When the user visits this URL, Keycloak will automatically authenticate them and redirect to your specified redirectUri.

Approach 2: Custom Keycloak Authenticator

For more control over the authentication logic, build a custom authenticator that skips password checks when your hash is validated:

  1. Develop a custom authenticator
    Create a Java class that implements Authenticator and overrides authenticate(). The logic should:

    • Check if the request includes a valid hash verification (passed from your controller)
    • If valid, mark the authentication as successful without checking a password
  2. Register the authenticator in Keycloak
    Package the authenticator as a JAR, deploy it to Keycloak, and add it to your realm's login flow (place it before the password authenticator and set it to skip password checks if valid).

  3. Pass validation context to Keycloak
    After your controller verifies the hash, redirect the user to Keycloak's login page with a custom parameter (e.g., validated_hash=true). Your custom authenticator will pick this up and complete authentication.

Approach 3: Direct Grant API with Temporary Password

If you prefer a simpler API-based flow (without custom code), use Keycloak's Direct Grant API with a temporary password:

  1. Create user and set a temporary password
    After verifying the hash, create the user in Keycloak and set a random, one-time password:

    String tempPassword = UUID.randomUUID().toString();
    CredentialRepresentation tempCred = new CredentialRepresentation();
    tempCred.setType(CredentialRepresentation.PASSWORD);
    tempCred.setValue(tempPassword);
    tempCred.setTemporary(true); // Forces user to reset on next login (optional)
    
    keycloak.realm("your-realm").users().get(userId).resetPassword(tempCred);
    
  2. Fetch an access token via Direct Grant
    Call Keycloak's token endpoint to get an access token for the user:

    curl -X POST "https://your-keycloak-instance/auth/realms/your-realm/protocol/openid-connect/token" \
         -H "Content-Type: application/x-www-form-urlencoded" \
         -d "username=user@example.com" \
         -d "password=${tempPassword}" \
         -d "grant_type=password" \
         -d "client_id=your-app-client" \
         -d "client_secret=your-client-secret"
    
  3. Complete login in your application
    Use the returned access token to set session cookies or authenticate the user in your frontend. You can also optionally disable password login for the user if they'll only use restricted access.

Critical Security Notes
  • Hash code security: Use HMAC-SHA256 or similar to generate the hash, tying it to unique user data (email, timestamp) and a secret key to prevent forgery.
  • Link expiration: Set a short TTL for both the hash code and Keycloak's login tokens to reduce misuse risk.
  • Admin API permissions: Ensure your backend service has the minimum required Keycloak admin permissions (e.g., manage-users, create-users) to avoid overprivileged access.

内容的提问来源于stack exchange,提问作者troger19

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:11:34