我尝试了许多角度adal库,但令牌的更新不是自动完成的。
这是我使用的配置。
在package.json
中"@types/adal": "^1.0.29",
"@types/adal-angular": "^1.0.0",
"adal-angular": "^1.0.17",
adal-angular附带两个脚本adal.js
和adal-angular.js
。我认为adal.angular.js
仅针对旧的angularjs
解决方案。所以我使用了adal.js和一个包装器@ types / adal。
并在adal.js
.angular-cli.json
"scripts": [
"../node_modules/adal-angular/lib/adal.js"
],
在我的angular 5应用程序中,我使用adal登录并向另一个网址上的网站发出请求api请求。
使用过的配置
JwtConfig: {
tenant: "a1d50521-9687-4e4d-a76d-xxxxxxxxx",
clientId: "8d708afe-2966-40b7-918c-xxxxxxxx",
isAngular: true
},
我的authService看起来像
import { } from "adal";
@Injectable()
export class AuthService {
private _config: adal.Config;
private _context: adal.AuthenticationContext;
constructor() {
Logging = {
level: 3,
log: function (message) {
console.log(message);
}
};
this._config = environment.JwtConfig;
this._context = new AuthenticationContext(this._config);
}
不需要记录,但可以启用adal.js记录
许多示例在localstorage中存储令牌,但此令牌仅在1小时内有效。为了解决这个问题,我每次都调用acquireToken。如果它已过期,它将为我提供缓存的令牌或续订。
acquireToken(): Observable<string> {
return new Observable<string>((subscriber: Subscriber<string>) => {
if (window.frameElement && window.frameElement.id === "adalIdTokenFrame")
subscriber.next(null);
else {
const user = this._context.getCachedUser();
return this._context.acquireToken(environment.JwtConfig.clientId, (message: string, token: string) => {
subscriber.next(token);
});
}
});
}
为了使这项工作正常,有许多棘手的事情。
更新是在隐藏的I帧中完成的,这是对Microsoft AD的请求
https://login.microsoftonline.com/xxxtenantIDxxx/oauth2/authorize?response_type=id_token&client_id=xxx-xx-x-xx
响应将重定向到http://localhost:4200/...
,这将在此隐藏的IFrame中启动另一个角度应用
此检查if (window.frameElement && window.frameElement.id === "adalIdTokenFrame")
将阻止无限循环的隐藏IFrame。
需要行const user = this._context.getCachedUser();
以便adal知道有用户并且将更新用户而不是用户必须登录的消息。
这似乎工作正常。如果令牌已过期New Date(profile.exp*1000)
几个小时。用户仍然可以续订此令牌。
有没有办法阻止我的Angular应用程序加载到隐藏的Iframe中?使用工作包装器或其他技巧?
答案 0 :(得分:6)
添加脚本以防止在隐藏帧中加载角度。这使得令牌的登录/续订更快。它可以防止在浏览器中第一次加载时开始树的角度。
此脚本可以添加到index.html。它检查它是否加载到隐藏帧中,解码令牌并防止加载角度。
<script>
if (window.parent && window.parent.AuthenticationContext) {
var self = window.parent._adalInstance;
var hash = window.location.hash;
if (self.isCallback(hash)) {
self.info("Returned from redirect url");
var requestInfo = self.getRequestInfo(hash);
var tokenReceivedCallback = self._callBackMappedToRenewStates[requestInfo.stateResponse];
self.saveTokenFromHash(requestInfo);
var token = requestInfo.parameters[self.CONSTANTS.ACCESS_TOKEN] || requestInfo.parameters[self.CONSTANTS.ID_TOKEN];
var tokenType = self.CONSTANTS.ACCESS_TOKEN;
var errorDesc = requestInfo.parameters[self.CONSTANTS.ERROR_DESCRIPTION];
var error = requestInfo.parameters[self.CONSTANTS.ERROR];
try {
if (tokenReceivedCallback)
tokenReceivedCallback(errorDesc, token, error, tokenType);
} catch (err) {
self.error("Error occurred in user defined callback function: " + err);
}
document.write('<style type="text/undefined">');
}
}
</script>
答案 1 :(得分:0)
有关更多信息,请参见Adal.js Wiki。在该页面上:
Adal使用iframe在后台静默更新令牌。 AAD 将令牌返回到令牌中指定的redirect_uri 请求(此redirect_uri必须在AAD中注册)。自从 响应是302,则结果对应于html redirect_uri在iframe中加载。通常是应用程序的 根/默认页面。这会导致应用程序重新加载。在其他情况下,如果 应用的根页面需要身份验证,这可能会导致嵌套 iframe或xframe拒绝错误。由于adal无法取消发布的302 通过AAD,它不能阻止redirect_uri加载到 iframe。但是,有一些解决方法可以避免 整个应用程序重新加载或其他原因导致的错误:
为iframe指定其他html:
将config上的redirect_uri属性设置为一个简单页面, 需要认证。您必须确保它与 redirect_uri在AAD门户中注册。这不会影响用户的 登录体验,因为Adal在用户开始 登录过程,并在登录后重定向到确切位置 完成。
请查看要点,以获取可以使用的模板html的示例。 您需要对html进行一些修改才能使其正常工作 使用您的特定应用程序: https://gist.github.com/tushargupta51/5fa6d000357120adbc8fd1d5c68853c4
主app.js文件中的条件初始化:如果您的应用程序是 结构类似于示例单页应用程序,其中有一个 定义应用程序的中央Javascript文件(示例中为app.js) 初始化,路由和其他内容,您可以使用if ... else 根据应用是否在iframe中加载而定。东西 像这样: https://gist.github.com/tushargupta51/78ce0b6bce998f6851abd02d91eb3a95
基本上他们在说
1)重定向到可以解析令牌但无法加载整个应用的页面,或者
2)重定向到应用根目录,并有条件地加载主要的JavaScript包。检测其是否为iframe,如果是,则不要加载应用捆绑包。
我认为上述 @Thom Kiesewetter 解决方案与他们建议的解决方法完全一致。如果脚本在iframe中,它基本上会停止在他编写的脚本之后加载任何JavaScript。