对于我们集成keycloak来说,你可能会遇到它没有实现的功能,这时需要对kc进行扩展,资源的扩展是其中一个方面,它需要实现RealmResourceProvider
和RealmResourceProviderFactory
两个接口,然后在KC启动之后,它可以被注册到IOC容器里,方便以后我们直接使用。
KC里的扩展是开闭原则OCP的完美体现,扩展在kc里叫SPI,它通过SPI的方式实现对功能的扩展,类似于面向接口的编程,通过META-INF/services里的文件进行注册,这类似于spring里的META-INF/spring.factories的功能。
public class WeixinUserResourceProviderFactory implements RealmResourceProviderFactory { private static final Logger logger = Logger.getLogger(WeixinUserResourceProviderFactory.class); public WeixinUserResourceProviderFactory() { System.err.println("WeixinUserResourceProviderFactory.init"); } /** * 资源提供者名称会在url上体现. * * @return */ @Override public String getId() { return "weixin-api"; } @Override public RealmResourceProvider create(KeycloakSession session) { return new WeixinUserResourceProvider(session); } @Override public void init(Scope config) { } @Override public void postInit(KeycloakSessionFactory factory) { } @Override public void close() { } }
public class WeixinUserResourceProvider implements RealmResourceProvider { private final KeycloakSession session; WeixinUserResourceProvider(KeycloakSession session) { this.session = session; } @Override public Object getResource() { return new WeixinUserResource(session); } @Override public void close() { } }
public class WeixinUserResource { private final KeycloakSession session; private final EntityManager em; private final RealmModel realm; public WeixinUserResource(KeycloakSession session) { this.session = session; realm = session.getContext().getRealm(); this.em = session.getProvider(JpaConnectionProvider.class).getEntityManager(); } @GET @NoCache @Produces(APPLICATION_JSON) @Path("user-detail") public UserDetail userDetail(@HeaderParam("Authorization") String authorization, @QueryParam("userId") String userId) { //.... }
对于上面的资源,我们可以通过{kc-host}/auth/realms/{realm-name}/weixin-api/user-detail
地址去访问它,其中,weixin-api表示当前spi factory的ID。
keycloak.services.social.weixin.rest.WeixinUserResourceProviderFactory