角度5 adal.js自动令牌更新负载角度两倍或更多

时间:2018-03-04 19:53:44

标签: angular azure-active-directory angular5 adal.js

我尝试了许多角度adal库,但令牌的更新不是自动完成的。

这是我使用的配置。

在package.json

"@types/adal": "^1.0.29",
"@types/adal-angular": "^1.0.0",
"adal-angular": "^1.0.17",

adal-angular附带两个脚本adal.jsadal-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中?使用工作包装器或其他技巧?

2 个答案:

答案 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。