Keycloak对接自定义用户校验Web服务及IDP配置技术咨询
Hey there! Let's work through this together since you're new to Keycloak and trying to tie your Java EE app's user database (via a web service) into Keycloak's authentication flow. First, let's clear up some confusion and break down your options step by step.
If your goal is to validate a username/password against your own web service and pull user data into Keycloak, OIDC is the better choice. SAML is designed for heavy enterprise-grade single sign-on (think legacy systems or cross-organization SSO), while OIDC is lighter, more modern, and easier to implement for custom user validation scenarios like yours.
You mentioned configuring an "id provider" in Keycloak, but let's clarify: IDPs are typically used to connect Keycloak to third-party identity systems (like Google, Facebook, or another SSO platform). Your use case—having Keycloak call your own web service to check if a user exists in your database—actually fits better with Keycloak's Custom Authenticator SPI or Custom User Provider. That said, if you already have a web service that you need to reuse, you can still use OIDC as an IDP. Let's cover both approaches.
Option 1: Using OIDC ID Provider (if you must reuse your existing web service)
First, your web service needs to support at least the Resource Owner Password Credentials Flow (note: this flow isn't recommended for production, but it's the simplest for password-based validation). Here's how to map the Keycloak settings to your service:
- Authorization URL: Only needed if you use the Authorization Code Flow (for redirect-based login). If you're using password validation directly, you might not need this—focus on the Token URL instead.
- Token URL: This is the endpoint on your web service where Keycloak sends the username and password for validation. Example:
http://your-web-service.com/api/auth/token - Client ID: A unique identifier you create to let your web service know the request is coming from Keycloak (like how you created a Client ID for your Java EE app in Keycloak).
- Client Secret: A secret string paired with the Client ID to secure the connection—your web service should validate this secret to ensure requests are legitimate.
Once these are configured, Keycloak will forward the user's login credentials to your web service's Token URL. Your service needs to return a valid OIDC token (with user claims like email, roles, etc.) if the credentials are correct, which Keycloak will then use to authenticate the user for your Java EE app.
Option 2: Custom Authenticator SPI (Recommended for your use case)
This approach is more aligned with Keycloak's design, as it lets you directly integrate your web service into Keycloak's authentication flow without treating it as a third-party IDP. Here's how to implement it:
Step 1: Set up your project
Create a Maven project and add Keycloak's core and SPI dependencies (match the version of your Keycloak instance):
<dependencies> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-core</artifactId> <version>22.0.5</version> <!-- Use your Keycloak version --> <scope>provided</scope> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-server-spi</artifactId> <version>22.0.5</version> <scope>provided</scope> </dependency> </dependencies>
Step 2: Write the custom authenticator
Create a class that implements Keycloak's Authenticator interface. This is where you'll call your web service to validate credentials and pull user data:
package com.yourcompany.keycloak.auth; import org.keycloak.authentication.AuthenticationFlowContext; import org.keycloak.authentication.Authenticator; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; public class WebServiceUserAuthenticator implements Authenticator { @Override public void authenticate(AuthenticationFlowContext context) { // Grab the username and password from the login form String username = context.getAuthenticationSession().getAuthenticatedUser().getUsername(); String password = context.getHttpRequest().getDecodedFormParameters().getFirst("password"); // Call your web service to validate credentials boolean isValidUser = validateUserWithWebService(username, password); if (isValidUser) { // Fetch additional user data from your web service UserProfile profile = fetchUserProfileFromWebService(username); // Attach the data to Keycloak's user object so your Java EE app can access it UserModel keycloakUser = context.getAuthenticationSession().getAuthenticatedUser(); keycloakUser.setSingleAttribute("full_name", profile.getFullName()); keycloakUser.setSingleAttribute("department", profile.getDepartment()); // Tell Keycloak the authentication was successful context.success(); } else { // Reject the login if credentials are invalid context.failure(context.getError().invalidCredentials()); } } // Replace these methods with your actual web service calls private boolean validateUserWithWebService(String username, String password) { // Use HttpClient or RestTemplate to call your service's validation endpoint return true; // Replace with real validation logic } private UserProfile fetchUserProfileFromWebService(String username) { // Call your service to get user details return new UserProfile("John Doe", "Engineering"); // Replace with real data } // Implement the remaining required interface methods @Override public void action(AuthenticationFlowContext context) {} @Override public boolean requiresUser() { return true; } @Override public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { return true; } @Override public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {} @Override public void close() {} } // Helper class for user profile data class UserProfile { private String fullName; private String department; public UserProfile(String fullName, String department) { this.fullName = fullName; this.department = department; } // Getters public String getFullName() { return fullName; } public String getDepartment() { return department; } }
Step 3: Register the authenticator
Create a file at src/main/resources/META-INF/services/org.keycloak.authentication.Authenticator with the full path to your authenticator class:
com.yourcompany.keycloak.auth.WebServiceUserAuthenticator
Step 4: Deploy and configure in Keycloak
- Package your project into a JAR file.
- Copy the JAR to your Keycloak instance's
providersdirectory. - Restart Keycloak.
- In the Keycloak admin console:
- Go to Authentication > Flows.
- Copy the default
Browserflow (click the three dots > Copy) and name it something likeCustom Web Service Flow. - Expand the copied flow's
Forms>Username Password Formsection. - Click Actions > Add Execution, select your custom authenticator from the list, and set its requirement to
REQUIRED. - Go to Authentication > Bindings, set the
Browser Flowto your new custom flow.
- If you're starting fresh, the Custom Authenticator SPI is the cleaner, more maintainable option.
- If you already have a web service that implements OIDC, go with the OIDC ID Provider route.
- Once set up, your Java EE app can access the user data from Keycloak via the access token or session attributes (just like you would with Keycloak's built-in users).
内容的提问来源于stack exchange,提问作者Vince

