我有一个要与身份服务器4集成的Angular SPA应用程序。
我正在尝试通过angular-auth-oidc-client库使用新的推荐身份验证流程。
我已经设置了一个Angular拦截器,该拦截器会在每次请求时执行,并尝试通过获取登录(如果用户未通过身份验证)来强制获取令牌。它的代码是这样的:
import { HttpInterceptor, HttpRequest, HttpEvent, HttpHandler} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { AuthService } from '../authentication/auth.service';
@Injectable()
export class TokenInterceptorService implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('INTERCEPTOR' + this.authService);
//// We retrieve the token, if any
let token = this.authService.getToken();
let newHeaders = req.headers;
if (!token) {
this.authService.login();
}
token = this.authService.getToken();
newHeaders = newHeaders.append('bearer', token);
//// Finally we have to clone our request with our new headers
//// This is required because HttpRequests are immutable
const authReq = req.clone({headers: newHeaders});
//// Then we return an Observable that will run the request
//// or pass it to the next interceptor if any
return next.handle(authReq);
}
}
AuthService实现如下所示
import { Injectable, OnDestroy, Inject } from '@angular/core';
import { OidcSecurityService, OpenIdConfiguration, AuthWellKnownEndpoints, AuthorizationResult, AuthorizationState } from 'angular-auth-oidc-client';
import { Observable , Subscription, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { HttpHeaders, HttpClient, HttpParams } from '@angular/common/http';
import { Router } from '@angular/router';
@Injectable()
export class AuthService implements OnDestroy {
isAuthorized = false;
public bearerToken: string | null = null;
public sessionState: number | null = null;
constructor(
private oidcSecurityService: OidcSecurityService,
private http: HttpClient,
private router: Router,
@Inject('BASE_URL') private originUrl: string,
@Inject('AUTH_URL') private authUrl: string,
) {
}
private isAuthorizedSubscription: Subscription = new Subscription;
ngOnDestroy(): void {
if (this.isAuthorizedSubscription) {
this.isAuthorizedSubscription.unsubscribe();
}
}
public initAuth() {
const openIdConfiguration: OpenIdConfiguration = {
stsServer: this.authUrl,
redirect_url: this.originUrl + 'callback',
client_id: 'myApp.api',
response_type: 'code',
scope: 'myApp.api',
post_logout_redirect_uri: this.originUrl,
forbidden_route: '/forbidden',
unauthorized_route: '/unauthorized',
silent_renew: true,
silent_renew_url: this.originUrl,
history_cleanup_off: true,
auto_userinfo: true,
log_console_warning_active: true,
log_console_debug_active: true,
max_id_token_iat_offset_allowed_in_seconds: 10,
};
const authWellKnownEndpoints: AuthWellKnownEndpoints = {
issuer:'.office.sbs',
jwks_uri: this.authUrl + '/.well-known/openid-configuration/jwks',
authorization_endpoint: this.authUrl + '/connect/authorize',
token_endpoint: this.authUrl + '/connect/token',
userinfo_endpoint: this.authUrl + '/connect/userinfo',
end_session_endpoint: this.authUrl + '/connect/endsession',
check_session_iframe: this.authUrl + '/connect/checksession',
revocation_endpoint: this.authUrl + '/connect/revocation',
introspection_endpoint: this.authUrl + '/connect/introspect',
};
this.oidcSecurityService.setupModule(openIdConfiguration, authWellKnownEndpoints);
if (this.oidcSecurityService.moduleSetup) {
this.doCallbackLogicIfRequired();
} else {
this.oidcSecurityService.onModuleSetup.subscribe(() => {
this.doCallbackLogicIfRequired();
});
}
this.isAuthorizedSubscription = this.oidcSecurityService.getIsAuthorized().subscribe((isAuthorized => {
this.isAuthorized = isAuthorized;
}));
this.oidcSecurityService.onAuthorizationResult.subscribe(
(authorizationResult: AuthorizationResult) => {
this.onAuthorizationResultComplete(authorizationResult);
});
}
private onAuthorizationResultComplete(authorizationResult: AuthorizationResult) {
console.log('Auth result received AuthorizationState:'
+ authorizationResult.authorizationState
+ ' validationResult:' + authorizationResult.validationResult);
if (authorizationResult.authorizationState === AuthorizationState.unauthorized) {
if (window.parent) {
// sent from the child iframe, for example the silent renew
this.router.navigate(['/unauthorized']);
} else {
window.location.href = '/unauthorized';
}
}
else if (authorizationResult.authorizationState === AuthorizationState.authorized) {
console.log("authenticated");
}
}
private doCallbackLogicIfRequired() {
//this.oidcSecurityService.authorizedCallbackWithCode(window.location.toString());
console.log(window.location);
const urlParts = window.location.toString().split('?');
const params = new HttpParams({
fromString: urlParts[1]
});
const code = params.get('code');
const state = params.get('state');
if (code && state && this.sessionState === null) {
this.sessionState = Math.random() * 50000;
this.oidcSecurityService.requestTokensWithCode(code, state, this.sessionState.toString());
}
}
getIsAuthorized(): Observable<boolean> {
return this.oidcSecurityService.getIsAuthorized();
}
login() {
console.log('start login');
this.oidcSecurityService.authorize();
}
logout() {
console.log('start logoff');
this.oidcSecurityService.logoff();
}
get(url: string): Observable<any> {
return this.http.get(url, { headers: this.getHeaders() })
.pipe(catchError((error) => {
this.oidcSecurityService.handleError(error);
return throwError(error);
}));
}
put(url: string, data: any): Observable<any> {
const body = JSON.stringify(data);
return this.http.put(url, body, { headers: this.getHeaders() })
.pipe(catchError((error) => {
this.oidcSecurityService.handleError(error);
return throwError(error);
}));
}
delete(url: string): Observable<any> {
return this.http.delete(url, { headers: this.getHeaders() })
.pipe(catchError((error) => {
this.oidcSecurityService.handleError(error);
return throwError(error);
}));
}
post(url: string, data: any): Observable<any> {
const body = JSON.stringify(data);
return this.http.post(url, body, { headers: this.getHeaders() })
.pipe(catchError((error) => {
this.oidcSecurityService.handleError(error);
return throwError(error);
}));
}
private getHeaders() {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json');
return this.appendAuthHeader(headers);
}
public getToken() {
const token = this.oidcSecurityService.getToken();
return token;
}
private appendAuthHeader(headers: HttpHeaders) {
const token = this.oidcSecurityService.getToken();
if (token === '') { return headers; }
const tokenValue = 'Bearer ' + token;
return headers.set('Authorization', tokenValue);
}
}
主要问题是,当我在angular-auth-oidc-client.js中命中要求令牌的请求时(下面的代码),请求在身份服务器和回调页面之间不断切换,而代码在不断命中方法doCallbackLogicIfRequired。
OidcSecurityService.prototype.requestTokensWithCodeProcedure$ =
// Code Flow with PCKE
/**
* @param {?} code
* @param {?} state
* @param {?} session_state
* @return {?}
*/
function (code, state, session_state) {
var _this = this;
/** @type {?} */
var tokenRequestUrl = '';
if (this.configurationProvider.wellKnownEndpoints && this.configurationProvider.wellKnownEndpoints.token_endpoint) {
tokenRequestUrl = "" + this.configurationProvider.wellKnownEndpoints.token_endpoint;
}
if (!this.oidcSecurityValidation.validateStateFromHashCallback(state, this.oidcSecurityCommon.authStateControl)) {
this.loggerService.logWarning('authorizedCallback incorrect state');
// ValidationResult.StatesDoNotMatch;
return throwError(new Error('incorrect state'));
}
/** @type {?} */
var headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/x-www-form-urlencoded');
/** @type {?} */
var data = oneLineTrim(templateObject_1 || (templateObject_1 = __makeTemplateObject(["grant_type=authorization_code&client_id=", "\n &code_verifier=", "\n &code=", "&redirect_uri=", ""], ["grant_type=authorization_code&client_id=", "\n &code_verifier=", "\n &code=", "&redirect_uri=", ""])), this.configurationProvider.openIDConfiguration.client_id, this.oidcSecurityCommon.code_verifier, code, this.configurationProvider.openIDConfiguration.redirect_url);
if (this.oidcSecurityCommon.silentRenewRunning === 'running') {
data = oneLineTrim(templateObject_2 || (templateObject_2 = __makeTemplateObject(["grant_type=authorization_code&client_id=", "\n &code_verifier=", "\n &code=", "\n &redirect_uri=", ""], ["grant_type=authorization_code&client_id=", "\n &code_verifier=", "\n &code=", "\n &redirect_uri=", ""])), this.configurationProvider.openIDConfiguration.client_id, this.oidcSecurityCommon.code_verifier, code, this.configurationProvider.openIDConfiguration.silent_renew_url);
}
return this.httpClient.post(tokenRequestUrl, data, { headers: headers }).pipe(map((/**
* @param {?} response
* @return {?}
*/
function (response) {
/** @type {?} */
var obj = new Object();
obj = response;
obj.state = state;
obj.session_state = session_state;
_this.authorizedCodeFlowCallbackProcedure(obj);
return undefined;
})), catchError((/**
* @param {?} error
* @return {?}
*/
function (error) {
_this.loggerService.logError(error);
_this.loggerService.logError("OidcService code request " + _this.configurationProvider.openIDConfiguration.stsServer);
return throwError(error);
})));
};
通过检查控制台日志,我可以看到我获得了令牌
VM1604 app.bundle.js:11364 INTERCEPTOR[object Object]
VM1604 app.bundle.js:1527 start login
VM1604 app.bundle.js:89392 BEGIN Authorize Code Flow, no auth data
VM1604 app.bundle.js:89392 AuthorizedController created. local state: 15821982471040.47561711387714610.5390697281765799
VM1604 app.bundle.js:75476 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
VM1604 app.bundle.js:89392 BEGIN authorized Code Flow Callback, no auth data
VM1604 app.bundle.js:89392 history clean up inactive
VM1604 app.bundle.js:89392 {access_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJFODdGRjgwRjhBMkQyMT…V9-uKxgRq46JSiVpZbUSm_d7GB07aO1k4SvRWmIqw20Fo7ADA", expires_in: 3600, token_type: "Bearer", state: "15821982471040.47561711387714610.5390697281765799", session_state: "45871.95561094084"}
VM1604 app.bundle.js:89392 authorizedCallback created, begin token validation
VM1604 app.bundle.js:89392 jwks_uri: https://mySecurityMachine.myDomain/authentication/.well-known/openid-configuration/jwks
VM1604 app.bundle.js:11364 INTERCEPTOR[object Object]
VM1604 app.bundle.js:1527 start login
VM1604 app.bundle.js:89392 BEGIN Authorize Code Flow, no auth data
VM1604 app.bundle.js:89392 AuthorizedController created. local state: 15821982471040.47561711387714610.5390697281765799
log.js:24 [HMR] Waiting for update signal from WDS...
log.js:24 [HMR] Waiting for update signal from WDS...
Navigated to https://localhost.myDomain:8083/callback?code=b30915bfb9a0f8ea838b685b467fd33c02c3e3282210e9ca11807665a8116d87&scope=cc.api&state=15821982471040.47561711387714610.5390697281765799
log.js:24 [HMR] Waiting for update signal from WDS...
angular-auth-oidc-client.js:392 STS server: https://mySecurityMachine.myDomain/authentication
angular-auth-oidc-client.js:392 Silent Renew is active, check if token in storage is active
angular-auth-oidc-client.js:392 <iframe id="myiFrameForSilentRenew" style="display: none;">…</iframe>
auth.service.ts:105 Location {href: "https://localhost.myDomain:8083/callback?code=b3…15821982471040.47561711387714610.5390697281765799", ancestorOrigins: DOMStringList, origin: "https://localhost.myDomain:8083", protocol: "https:", host: "localhost.myDomain:8083", …}
如
所示VM1604 app.bundle.js:89392 {access_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJFODdGRjgwRjhBMkQyMT…V9-uKxgRq46JSiVpZbUSm_d7GB07aO1k4SvRWmIqw20Fo7ADA", expires_in: 3600, token_type: "Bearer", state: "15821982471040.47561711387714610.5390697281765799", session_state: "45871.95561094084"}
要重定向到所需页面我缺少什么?
答案 0 :(得分:0)
尝试这个受欢迎的客户angular-oauth2-oidc 有一些说明,一切都开始起作用。 此外,该软件包还包含一个很棒的authservice,您将不再需要authservice
答案 1 :(得分:0)
我最终要做的是使用
将请求网址存储在TokenInterceptorService中的本地存储中inv$start_year_month <- factor(inv$start_year_month, levels=paste(unique(format(inv$Month_Due, "%Y")), month.name, sep="-"))
我将redirectUri配置为将我重定向到myApp / callback端点,在该端点上component.ts类检查本地存储上是否设置了URL值。如果有,它将重定向到它
private currentUrlIndex = 'UrlBeforeLoginRedirect';
console.log("After the login will redirect to " + window.location.href);
if(this.getFromLocalStorage(this.currentUrlIndex) == null)
this.setOnLocalStorage(this.currentUrlIndex, window.location.href);
this.authService.login();
let tokenFromNewAuthentication = this.authService.getToken();
resultingToken = tokenFromNewAuthentication;
我喜欢这个解决方案,因为它重定向到最初请求的url(读取特定记录),而不是像烘焙解决方案那样重定向到首页。