我有两个不同的应用程序:分别是 Application1 和 Application2。
我已经将Application2与 Keycloak 集成,可以使用 Keycloak 的登录页面登录到该应用程序。
现在我想要的是,如果我在没有 Keycloak 的情况下登录到我的 Application1,我应该能够调用一些 Keycloak 的 API 来登录到 Application2(而无需呈现 Keycloak 的登录页面)。
这可行吗?如果可以,怎么做呢?
任何帮助将不胜感激。
谢谢
我有两个不同的应用程序:分别是 Application1 和 Application2。
我已经将Application2与 Keycloak 集成,可以使用 Keycloak 的登录页面登录到该应用程序。
现在我想要的是,如果我在没有 Keycloak 的情况下登录到我的 Application1,我应该能够调用一些 Keycloak 的 API 来登录到 Application2(而无需呈现 Keycloak 的登录页面)。
这可行吗?如果可以,怎么做呢?
任何帮助将不胜感激。
谢谢
您事实上正在要求用户相信应用程序1会安全地管理他们的Keycloak凭据。这并不推荐,因为:
但是,如果您控制并且可以信任应用程序1并且由于传统或其他原因需要执行此操作,则可以在Keycloak客户端定义中启用名为“Direct Access”的资源所有者凭据流,然后将用户的凭据作为form-urlencoded
数据类型进行POST请求。
https://<keycloak-url>/auth/realms/<realm>/protocol/openid-connect/token
参数将是
grant_type=password
client_id=<Application1's client id>
client_secret=<the client secret>
username=<the username>
password=<the password>
scope=<space delimited list of scope requests>
如果凭据无效,则响应将是一个有效的JWT对象或4xx错误。
curl http://localhost:8080/service/secured -H "Authorization: bearer $TOKEN"
请参阅获取令牌并调用服务。 - Anunayimport org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@Component
public class AnotherServiceClient {
public TypeOfObjectReturnedByAnotherService getFromAnotherService() {
RestTemplate restTemplate = new RestTemplate();
String endpoint = "http://localhost:40030/another/service/url";
String bearerToken = getAuthorizationToken();
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "bearer " + bearerToken);
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<TypeOfObjectReturnedByAnotherService> response = restTemplate.exchange(endpoint, HttpMethod.GET, entity, TypeOfObjectReturnedByAnotherService.class);
return response.getBody();
}
private String getAuthorizationToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SimpleKeycloakAccount details = (SimpleKeycloakAccount) authentication.getDetails();
KeycloakPrincipal<?> keycloakPrincipal = (KeycloakPrincipal<?>) details.getPrincipal();
RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) getPrincipal().getKeycloakSecurityContext();
return context.getTokenString();
}
}
class KeyCloakAuthView(
viewsets.GenericViewSet,
mixins.CreateModelMixin,
):
def create(self, request, *args, **kwargs):
headers = {
'Content-type': 'application/x-www-form-urlencoded',
}
payload = {
"client_id": settings.KEYCLOAK_CLIENT_ID,
"client_secret": settings.KEYCLOAK_CLIENT_SECRET,
"scope": settings.KEYCLOAK_SCOPE,
"grant_type": settings.KEYCLOAK_GRANT_TYPE,
"username": "<username>",
"password": "<passwd>",
}
rsp = requests.post(
settings.KEYCLOAK_AUTH_URL,
headers=headers,
data=payload,
)
return Response(
rsp.json(), status=status.HTTP_201_CREATED,
)
KEYCLOAK_REALM = '<realm>'
KEYCLOAK_GRANT_TYPE = 'password'
KEYCLOAK_SCOPE = 'openid'
KEYCLOAK_CLIENT_ID = '<client-id>'
KEYCLOAK_CLIENT_SECRET = '<client-secret>'
KEYCLOAK_AUTH_URL = f"http://localhost:8080/realms/{KEYCLOAK_REALM}/protocol/openid-connect/token"