使用IDP(KeyCloak)的Angular Oauth代码流验证
我正在尝试与Angular项目中的身份提供商(KeyCloak)集成。我正在为此目的使用“ Angular-Oauth2-oidc”库。
因此,我能够在单击按钮时从主页上将用户从主页重定向到IDP的登录页面,并在成功登录后将我重定向到原始页面。到目前为止还不错,但是我的问题是,在登录过程之后,不会将包括令牌在内的会话信息设置为我的浏览器的会话存储。如果我重复该过程(再次调用登录函数),则将其正确设置。
这是我到目前为止使用的代码;
auth.service.ts
constructor(private oauthService: OAuthService) {}
authConfig: AuthConfig = {
issuer: environment.keycloak.issuerAddress,
redirectUri: window.location.origin + '/home',
clientId: environment.keycloak.clientId,
scope: environment.keycloak.scope,
responseType: environment.keycloak.responseType,
disableAtHashCheck: environment.keycloak.disableAtHashCheck,
showDebugInformation: environment.keycloak.showDebugInformation,
}
login(): Promise<any> {
return new Promise<void>((resolveFn, rejectFn) => {
this.initLogin().then(() => {
resolveFn();
}).catch(function(e){
rejectFn(e);
});
});
}
private initLogin(): Promise<any> {
return new Promise<void>((resolveFn, rejectFn) => {
this.oauthService.configure(this.authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(() => {
if (this.oauthService.hasValidAccessToken()) {
this.oauthService.setupAutomaticSilentRefresh();
resolveFn();
}else {
this.oauthService.initCodeFlow();
resolveFn();
}
}).catch(function(e){
rejectFn("Identity Provider is not reachable!");
});
});
}
home.component.ts
login(): void {
this.authService.login().then(() => {
//
}).catch((e) =>{
//
});
}
总而言之,我要做的就是;
- 当用户单击登录按钮时,配置Oauthservice并尝试登录。
- 如果已经有有效的访问令牌,则只需设置无声刷新并返回即可。
- 如果没有有效的访问令牌,请启动代码流并重定向到IDP的登录页面。
- 如果登录尝试失败,则例外,请告诉用户IDP不可用。
注意:如果我改为在构造函数中进行oauthservice配置,并且仅在用户想要登录时调用oauthservice.initcodeflow()方法,则可以正常工作。我之所以没有在构造函数中配置它的原因是,我希望能够告诉用户当用户单击登录按钮时,IDP不可用。
I'm trying to integrate with an identity provider (Keycloak in my case) in my Angular project. I'm using "angular-oauth2-oidc" library for that purpose.
So, I'm able to redirect a user from my home page to the login page of IDP on a button click, and it redirects me back to my original page after a successful login. So far so good, but my problem is that after the login process, session information including token is not set to my browser's session storage. If I repeat the process (calling the login function again), it then sets them correctly.
Here are the codes that I've worked on so far;
auth.service.ts
constructor(private oauthService: OAuthService) {}
authConfig: AuthConfig = {
issuer: environment.keycloak.issuerAddress,
redirectUri: window.location.origin + '/home',
clientId: environment.keycloak.clientId,
scope: environment.keycloak.scope,
responseType: environment.keycloak.responseType,
disableAtHashCheck: environment.keycloak.disableAtHashCheck,
showDebugInformation: environment.keycloak.showDebugInformation,
}
login(): Promise<any> {
return new Promise<void>((resolveFn, rejectFn) => {
this.initLogin().then(() => {
resolveFn();
}).catch(function(e){
rejectFn(e);
});
});
}
private initLogin(): Promise<any> {
return new Promise<void>((resolveFn, rejectFn) => {
this.oauthService.configure(this.authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(() => {
if (this.oauthService.hasValidAccessToken()) {
this.oauthService.setupAutomaticSilentRefresh();
resolveFn();
}else {
this.oauthService.initCodeFlow();
resolveFn();
}
}).catch(function(e){
rejectFn("Identity Provider is not reachable!");
});
});
}
home.component.ts
login(): void {
this.authService.login().then(() => {
//
}).catch((e) =>{
//
});
}
In summary, what I'm trying to do is that;
- When the user clicks on login button, configure the oauthService and try to login.
- If there's already a valid access token, then just setup a silent refresh and return.
- If there's no valid access token, then start the code flow and redirect to IDP's login page.
- If login try is failed with an exception, tell the user that IDP is not available.
Note: If I instead do the oauthService configuration in the constructor, and only call the oauthService.initCodeFlow() method when the user wants to login, then it works fine. The reason I'm not configuring it in constructor is that I want to be able to tell the user that IDP is not available when the user clicks on login button.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
I find it cleanest to
它将等待授权逻辑为
iSdoneloDADing $
,以确保完成所有ASYNC授权boottrapping。然后,它检查用户是否已进行身份验证,如果没有,则将用户登录,但请记住参数中的目标页面登录(...)
。当用户返回您的应用程序时,该url
将提供给您。在您的应用程序的登录顺序中(以下是我的示例)您可以读取此
state
,并使用它将用户发送到最初的意图页面。现在应该允许后卫,因为用户已登录。这是登录顺序的相关部分:
I find it cleanest to create a guard that enforces login. You can then now decide to put that guard on all your routes, but it also allows you later to make exceptions to that. For example an FAQ page in your app might be publicly available? To duplicate said guard's code here:
It will wait for authorization logic to be
isDoneLoading$
just to make sure all async authorization bootstrapping is done. It then checks if the user is authenticated, and if not sends the user off to log in, but remembers the targeted page in the parameter tologin(...)
. Thaturl
will be provided back to you when the user returns to your application.In the login sequence of your app (here's my sample) you can read this
state
and use it to send the user to the originally intended page. The guard should now allow this, because the user has since signed in.Here's the relevant part of the login sequence to do this: