javascript - Angularjs oauth 弹出窗口,等待 JSON 响应

标签 javascript json angularjs oauth-2.0 passport.js

我需要发出 oauth 请求,并且我想在新窗口中启动该请求。

我知道我可以像这样打开窗口:

var authWindow = $window.open("/auth/google/signin", "");

我的服务器将处理回调并使用 JSON 进行响应:

 app.get('/auth/google/signin',
    passport.authenticate('google', { scope: 'https://www.googleapis.com/auth/plus.login'}),
    function(req, res, next) {
      // The request will be redirected to Google for authentication, so this
      // function will not be called.
    }
  );

app.get('/auth/google/callback',
    function(req, res, next) {
      passport.authenticate('google', function(err, user, info) {
        console.log('google authenticate callback');

        // do some stuff, then send back token and user...

        res.json({
          token:token,
          user: user
        });

      })(req, res, next);
    }
  );

我需要等到弹出窗口重定向到/auth/google/callback 并且 JSON 数据从服务器返回。

如何等待来自服务器的重定向和 JSON 响应?

等待并获得 JSON 数据后,返回数据的最佳方式是什么?打回来? postMessage()?

最佳答案

当然可以。
这是我的解决方案:使用 JS 和 Nodejs 作为后端。
主要技巧是:window.postMessage
主要流程是:
1. 客户端询问注册页面,服务器响应。
2. 注册页面触发oauth流程,会使用“window.open(” http://your_server/oauth_page “)”
3. oauth_page 做几件事

   a. Check the state(default/success)   
   b. if in dedault state, using window.opener.postMessages('ready','*')  
      to tell main window(signup page) I am ready.
      Then signup page would listen messages and return which oauth url assigned.  
      Because I have several oauth methods in one page(Github/Google+/Facebook)  
   c. The oauth_page would send XHR request to server.  
   d. server would send redirect_url back to oauth_page.  
   e. oauth_page would use "window.location_url" to redirect. Now you can see the authorization page.  
   f.The authorization result would send back to server.  
   g.server would run exchange code, take access_token and get info you wanted.... I supposed you know this process.(passport library do.)  
   h.return the oauth_page to the same child window! The magic is that window.opener is still the signup page,so you can send result back as before.
 

4.The signup page would recieve the result!.


It looks quite long process but quite simple in code. Here is my signup page code

doctype html
html
    head
        title= title
    body
        h1= title
        p Welcome to #{title}
        button(id="github-oauth" data-oauth-server-url="github") Sign up by Github
        button(id="google-oauth" data-oauth-server-url="google") Sign up by Google
        button(id="facebook-oauth" data-oauth-server-url="facebook") Sign up by Facebook
        script(type="text/javascript").
            window.onload = function() {
                var oauth_page;
                var oauth_server_url;
                function createOauthButtonListner(elem) {
                    elem.addEventListener("click", function () {
                        oauth_page = window.open("http://localhost:3000/oauth_page");
                        //determine which button is triggered.
                        oauth_server_url = elem.getAttribute("data-oauth-server-url");
                        console.log(oauth_server_url);
                    })
                };
                window.addEventListener('message', function (e) {
                    if (e.data == "ready") {
                        // send oauth url
                        oauth_page.postMessage(oauth_server_url, "http://localhost:3000");
                    } else {
                        // return oauth resut
                        console.log(e.data);
                    }
                }, false);
                createOauthButtonListner(document.getElementById("github-oauth"));
                createOauthButtonListner(document.getElementById("google-oauth"));
                createOauthButtonListner(document.getElementById("facebook-oauth"));
            }

这是我的 Oauth_page

doctype html
html
    head
        title= "Oauth Page"
    body
        p Welcome to Oauth page
        p#status #{status}
        p#content #{content}
        script(type="text/javascript").
            window.onload = function(){
                // return msg to host window
                if (document.getElementById('status').innerHTML == 'success') {
                    window.opener.postMessage(document.getElementById('content').innerHTML, '*');
                    window.close();
                }else if(document.getElementById('status').innerHTML == 'default'){
                    window.opener.postMessage('ready', '*');
                }
                // redirect to oauth page
                window.addEventListener('message', function (e) {
                    console.log(window);
                    if (e.origin != "http://localhost:3000") {
                        console.log("error");
                        return;
                    } else {
                        if (document.getElementById('status').innerHTML == 'default') {
                            var xhttp = new XMLHttpRequest();
                            xhttp.open("GET", e.data, true);
                            xhttp.send();
                            xhttp.onreadystatechange = function () {
                                if (xhttp.readyState == 4 && xhttp.status == 200) {
                                    window.location.href = JSON.parse(xhttp.responseText).redirect_url;
                                }
                            };
                        }
                    }
                }, false);
            };

我的服务器端代码(相当困惑:P)

router.get('/oauth_page', function (req, res, next) {
    res.render('oauth', {status: 'default', content: 'none'});
})

// for github oauth
router.get('/github', function(req, res){
  var github_oauth_url = "https://github.com/login/oauth/authorize" +
      "?client_id=" + github_client_id  +
      "&scope=user" ;
  res.send(JSON.stringify({"redirect_url":github_oauth_url}));
});

router.get('/github/callback', function(req, res){
    var code = req.query.code;
    var token_option = {
        url:"https://github.com/login/oauth/access_token",
        method:"POST",
        form:{
            code: code,
            client_id: github_client_id,
            client_secret: github_secret_id
        }
    };
  request(token_option, function(err, response, body){
      if(err){
          res.send(response);
      }
      var regex = /\=([a-zA-Z0-9]+)\&([a-zA-Z])+\=([a-zA-Z0-9]+)/;
      var result = body.match(regex);
      console.log(result, body);
      var token = result[1];

      var info_option = {
          url:"https://api.github.com/user",
          method:"GET",
          headers:{
              "User-Agent": "Awesome-Octocat-App",
              "Authorization":"token "+ token
          }
      }
      request(info_option, function(err, response, body){
         if(err){
             res.send(err);
         }
          res.render('oauth', {status: 'success', content:body});
      });
  });
});

在注册页面,打开控制台即可看到结果。
请随时问我问题;)
我花了一周的时间为此工作。
希望它可以帮助你。

关于javascript - Angularjs oauth 弹出窗口,等待 JSON 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32058337/

相关文章:

javascript - 最佳 ASP.NET 动态用户控件加载方法

javascript - Web 应用程序中的桌面屏幕截图

java - Android:处理可以是字符串或数组的 json 对象

java - 使用 spring Rest 以自定义格式显示 json

javascript - 根据 Firebase 中的类别检索数据

javascript - AngularJS - 如果用户登录,则显示/隐藏导航项目

javascript - 如何在 google.maps.places.PlacesService(map).textSearch() 中添加回调函数

javascript - 在构建 bundle 时如何删除未使用的代码?

r - 使用 data.table 写入和加载 JSON 字符串

javascript - 将函数分配给变量 angularjs