Apache Shiro:如何在shiro.ini中配置JWT结合Keycloak实现客户端认证
Hey there! As someone new to both Apache Shiro and Keycloak, I get that configuring JWT can feel a bit overwhelming at first. Let's break this down into clear, actionable steps to get you up and running.
1. First, Add Required Dependencies
Shiro doesn't include JWT support out of the box, so you'll need to add a Shiro JWT integration library along with Keycloak's JWT utilities. If you're using Maven, add these to your pom.xml:
<!-- Shiro Core --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.12.0</version> </dependency> <!-- Shiro Web (for web applications) --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.12.0</version> </dependency> <!-- Keycloak JWT Utilities --> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-core</artifactId> <version>22.0.5</version> </dependency> <!-- Community Shiro JWT Integration --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>shiro-jwt</artifactId> <version>2.0.0</version> </dependency>
2. Create a Custom Keycloak JWT Realm
You'll need a custom Shiro Realm to validate JWT tokens issued by Keycloak. This realm handles verifying the token's signature, parsing user identity/roles, and granting permissions. Here's a simplified example:
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.keycloak.jose.jwk.JWK; import org.keycloak.jose.jwk.JWKParser; import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInputException; import org.keycloak.representations.AccessToken; import java.security.PublicKey; public class KeycloakJwtRealm extends AuthorizingRealm { // Replace with your Keycloak realm's public key (copy from Keycloak admin console) private static final String KEYCLOAK_PUBLIC_KEY = "YOUR_KEYCLOAK_PUBLIC_KEY_HERE"; @Override public boolean supports(AuthenticationToken token) { // Only handle JWT tokens return token instanceof JwtToken; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { JwtToken jwtToken = (JwtToken) token; String jwt = jwtToken.getToken(); try { // Parse and validate JWT using Keycloak's utilities JWSInput jwsInput = new JWSInput(jwt); JWK jwk = JWKParser.create().parse(KEYCLOAK_PUBLIC_KEY); PublicKey publicKey = jwk.toPublicKey(); // Verify signature and parse access token AccessToken accessToken = jwsInput.readJsonContent(AccessToken.class); accessToken.verify(publicKey); // Return authentication info with the user's username as principal return new SimpleAuthenticationInfo(accessToken.getPreferredUsername(), jwt, getName()); } catch (JWSInputException e) { throw new AuthenticationException("Invalid JWT token", e); } } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); // Extract roles from the JWT's realm access claims AccessToken accessToken = (AccessToken) principals.getPrimaryPrincipal(); authorizationInfo.setRoles(accessToken.getRealmAccess().getRoles()); return authorizationInfo; } }
3. Configure Shiro.ini
Now wire up the custom realm and JWT settings in your shiro.ini file:
# 1. Define your custom Keycloak JWT Realm [keycloakJwtRealm] class=com.yourpackage.KeycloakJwtRealm # 2. Set SecurityManager to use the realm [securityManager] realms=$keycloakJwtRealm # 3. Configure JWT Authentication Filter [jwtFilter] class=com.github.theborakompanioni.shiro.jwt.JwtAuthFilter # HTTP header where JWT is sent (standard is Authorization) jwtHeader=Authorization # Prefix for the token (e.g., "Bearer ") jwtTokenPrefix=Bearer # 4. Define web filter chain rules [urls] # Protect all API endpoints with JWT validation /api/** = jwtFilter # Allow public access to these paths /public/** = anon
4. Keycloak Pre-Setup Steps
Before testing, complete these in Keycloak:
- Create a new realm (or use the default)
- Create a client for your app with Access Type set to
bearer-only - Navigate to your realm's Keys tab, copy the public key, and paste it into your
KeycloakJwtRealmclass - Generate a test JWT token via Keycloak's token endpoint (use tools like Postman or curl)
5. Test the Setup
Send a request to your protected endpoint with the JWT token in the Authorization header:
Authorization: Bearer YOUR_KEYCLOAK_GENERATED_JWT_TOKEN
Shiro will use your custom realm to validate the token, authenticate the user, and grant access based on their roles.
If you run into issues, double-check:
- The public key in your realm matches Keycloak's exactly
- The JWT token hasn't expired
- The Keycloak client is configured with
bearer-onlyaccess type
Let me know if you hit any roadblocks—I’m here to help!
内容的提问来源于stack exchange,提问作者Rakesh Kumar

