te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - Oauth 2 popup with Angular 2 - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Oauth 2 popup with Angular 2 - Stack Overflow

programmeradmin4浏览0评论

I'm upgrading/rewriting an existing angular app to use angular2. My problem is that I want to open a OAuth flow in a new pop up window and once the OAuth flow is pleted use window.postMessage to municate back to the angular 2 app that the OAuth flow was successful.

Currently what I have is in the angular 2 service is

export class ApiService { 
    constructor(private _loggedInService: LoggedInService) {
        window.addEventListener('message', this.onPostMessage, false);
     }

    startOAuthFlow() {
       var options = 'left=100,top=10,width=400,height=500';
       window.open('http://site/connect-auth', , options);
    }

    onPostMessage(event) {
      if(event.data.status === "200") {
          // Use an EventEmitter to notify the other ponents that user logged in
          this._loggedInService.Stream.emit(null);
      }
    }

}

This template that is loaded at the end of the OAuth flow

<html>
  <head>
    <title>OAuth callback</title>
    <script>
      var POST_ORIGIN_URI = 'localhost:8000';
      var message = {"status": "200", "jwt":"2"};
      window.opener.postMessage(message, POST_ORIGIN_URI);
      window.close();
    </script>
  </head>
</html>

Using window.addEventListener like this seems to pletely break the angular 2 app, dereferencing this.

So my question is can I use window.addEventListener or should I not use postMessage to municate back to the angular2 app?

** Complete angular2 noob so any help is appreciated

I'm upgrading/rewriting an existing angular app to use angular2. My problem is that I want to open a OAuth flow in a new pop up window and once the OAuth flow is pleted use window.postMessage to municate back to the angular 2 app that the OAuth flow was successful.

Currently what I have is in the angular 2 service is

export class ApiService { 
    constructor(private _loggedInService: LoggedInService) {
        window.addEventListener('message', this.onPostMessage, false);
     }

    startOAuthFlow() {
       var options = 'left=100,top=10,width=400,height=500';
       window.open('http://site/connect-auth', , options);
    }

    onPostMessage(event) {
      if(event.data.status === "200") {
          // Use an EventEmitter to notify the other ponents that user logged in
          this._loggedInService.Stream.emit(null);
      }
    }

}

This template that is loaded at the end of the OAuth flow

<html>
  <head>
    <title>OAuth callback</title>
    <script>
      var POST_ORIGIN_URI = 'localhost:8000';
      var message = {"status": "200", "jwt":"2"};
      window.opener.postMessage(message, POST_ORIGIN_URI);
      window.close();
    </script>
  </head>
</html>

Using window.addEventListener like this seems to pletely break the angular 2 app, dereferencing this.

So my question is can I use window.addEventListener or should I not use postMessage to municate back to the angular2 app?

** Complete angular2 noob so any help is appreciated

Share Improve this question asked Jan 5, 2016 at 16:14 roykaroyka 1,6102 gold badges13 silver badges10 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 6

I have a plete Angular2 OAuth2 skeleton application on Github that you can refer to.

It makes use of an Auth service for OAuth2 Implicit grants that in turn uses a Window service to create the popup window. It then monitors that window for the access token on the URL.

You can access the demo OAuth2 Angular code (with Webpack) here.

Here is the login routine from the Auth service, which will give you an idea of what's going on without having to look at the entire project. I've added a few extra ments in there for you.

public doLogin() {
    var loopCount = this.loopCount;
    this.windowHandle = this.windows.createWindow(this.oAuthTokenUrl, 'OAuth2 Login');

    this.intervalId = setInterval(() => {
        if (loopCount-- < 0) { // if we get below 0, it's a timeout and we close the window
            clearInterval(this.intervalId);
            this.emitAuthStatus(false);
            this.windowHandle.close();
        } else { // otherwise we check the URL of the window
            var href:string;
            try {
                href = this.windowHandle.location.href;
            } catch (e) {
                //console.log('Error:', e);
            }
            if (href != null) { // if the URL is not null
                var re = /access_token=(.*)/;
                var found = href.match(re);
                if (found) { // and if the URL has an access token then process the URL for access token and expiration time
                    console.log("Callback URL:", href);
                    clearInterval(this.intervalId);
                    var parsed = this.parse(href.substr(this.oAuthCallbackUrl.length + 1));
                    var expiresSeconds = Number(parsed.expires_in) || 1800;

                    this.token = parsed.access_token;
                    if (this.token) {
                        this.authenticated = true;
                    }

                    this.startExpiresTimer(expiresSeconds);
                    this.expires = new Date();
                    this.expires = this.expires.setSeconds(this.expires.getSeconds() + expiresSeconds);

                    this.windowHandle.close();
                    this.emitAuthStatus(true);
                    this.fetchUserInfo();
                }
            }
        }
    }, this.intervalLength);
}

Feel free to ask if you have any questions or problems getting the app up and running.

So with a bit of investigation found out the problem. I was de-referencing this. This github wiki helped me understand it a bit more.

To solve it for my case needed to do a couple of things. Firstly I created a service that encapsulated the adding of an eventListener

import {BrowserDomAdapter} from 'angular2/platform/browser';

export class PostMessageService {
   dom = new BrowserDomAdapter();
   addPostMessageListener(fn: EventListener): void {
     this.dom.getGlobalEventTarget('window').addEventListener('message', fn,false)
   }
}

Then using this addPostMessageListener I can attach a function in my other service to fire

constructor(public _postMessageService: PostMessageService,
    public _router: Router) {
    // Set up a Post Message Listener
    this._postMessageService.addPostMessageListener((event) => 
          this.onPostMessage(event)); // This is the important as it means I keep the reference to this

}

Then it works how I expected keeping the reference to this

I think this is the Angular2 way:

(Dart code but TS should be quite similar)

@Injectable()
class SomeService {
  DomAdapter dom;
  SomeService(this.dom) {
    dom.getGlobalEventTarget('window').addEventListener("message", fn, false);
  }
}

I fiddled around with this for ages but in the end, the most robust way for me was to redirect the user to the oath page

window.location.href = '/auth/logintwitter';

do the oath dance in the backend (I used express) and then redirect back to a receiving front end page...

res.redirect(`/#/account/twitterReturn?userName=${userName}&token=${token}`);

There are some idiosyncracies to my solution because e.g. I wanted to use only JsonWebToken on the client regardless of login type, but if you are interested, whole solution is here.

https://github./JavascriptMick/learntree

发布评论

评论列表(0)

  1. 暂无评论