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

Apache Shiro:如何在shiro.ini中配置JWT结合Keycloak实现客户端认证

Setting Up JWT Authentication in Shiro.ini with Keycloak as Authorization Server

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 KeycloakJwtRealm class
  • 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-only access type

Let me know if you hit any roadblocks—I’m here to help!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:13:39