需要协助在 VueJS 应用程序中集成 OAuth [英] Need Assistance in integrating OAuth in VueJS App

查看:49
本文介绍了需要协助在 VueJS 应用程序中集成 OAuth的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在端口 8080 上运行的前端 VueJS 应用程序和一个在端口 3000 上运行的 NodeJS 服务器.现在我需要集成一个辅助应用程序,我需要从我的 VueJS 应用程序中单击按钮来访问它的 API.我目前的服务器架构如下,需要知道是需要为Authorization服务器新建一个服务器还是可以和3000端口集成?

如果我需要创建一个新的服务器授权服务器,我如何添加它?设置是什么.我面临的问题是,我尝试将授权服务器与端口 3000 的后端服务器集成,我能够使用资源服务器,但是我只能通过重定向 url 调用 add API 调用如下图(OAuth.js):

router.get('/oauth', async (req: Request, res: Response)=>{oAuthSession = new OAuth(config.oauthRequestTokenUri, config.oauthAccessTokenUri, config.clientKey, config.clientSecret,config.oAuthVersion, config.authorizeCallbackUri, config.oAuthSignatureMethod, config.oAuthNonceSize, config.oAuthCustomHeaders);......}router.get('/callback', async (req: Request, res: Response)=>{token.verifier = req.query.oauth_verifier;l('----- 回调 - 收到验证器 -----');l(JSON.stringify(tokens, null, 2));l('----- 请求访问令牌和秘密 -----');oAuthSession.getOAuthAccessToken(tokens.requestToken, tokens.requestTokenSecret, tokens.verifier, function (error, token, secret, results) {token.accessToken = 令牌;token.accessTokenSecret = 秘密;l('----- 访问令牌和收到的秘密 -----');l('StatusCode =>' + results.statusCode);l(JSON.stringify(tokens, null, 2));oAuthSession.get(config.platformBaseUri, tokens.accessToken, tokens.accessTokenSecret, function (error, responseData, result) {l('StatusCode =>' + result.statusCode);l('----- 现在准备进行 OAuth 认证调用-----');res.redirect(`http://localhost:3000/auth/add?accessToken=${tokens.accessToken}&accessTokenSecret=${tokens.accessTokenSecret}`)重发();

但是当我尝试从前端 VueJS 调用 API 调用时,没有调用 API 调用.它仅通过上述代码中显示的重定向 URL 触发.如果添加了新服务器(授权服务器),应如何从前端使用 API 调用?我是这个领域的新手,如果我的问题有任何不明白的地方,请告诉我,我会尽力澄清.

解决方案

从架构上来说,你应该:

  • 1 个 OAuth 服务器
  • 1 个前端
  • 2 个 API
  • 1 个 OAuth 客户端(如果您的两个 API 都接受来自您的 OAuth 服务器的令牌,则可能)

前端是 OAuth 客户端.

因此,您的 VueJS 客户端应该:

  1. 从 OAuth 服务器获取令牌
  2. 调用 API 1
  3. 在按钮处理程序(或其他)中,调用 API 2

两个 API 都应验证提供给它们的令牌,以确保它们来自 OAuth 服务器,值得信赖.

这是一个示例(sans-OAuth 服务器和 sans-API),展示了客户端/前端的工作方式.派生自本示例,其中包含更多信息.

<html lang="en"><头><元字符集=utf-8"><title>公共客户示例</title><身体><h1>公共客户样本</h1><button id="startButton">启动 OAuth 流程</button><span id="result"></span><div id="应用程序"><button v-on:click="callApi1">调用 API 1</button><button v-on:click="callApi2">调用 API 2</button>{{信息}}

<script src=https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script src=https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><脚本>const authorizeEndpoint = "https://localhost:8443/dev/oauth/authorize";const tokenEndpoint = "https://localhost:8443/dev/oauth/token";const clientId = "public_client";var access_token;如果 (window.location.search && window.location.search.length > 0) {var args = new URLSearchParams(window.location.search);var code = args.get(code");如果(代码){var xhr = new XMLHttpRequest();xhr.onload = 函数(){var response = xhr.response;var 消息;如果(xhr.status == 200){var access_token = response.access_token;axios.defaults.headers.common["Authorization"] = "Bearer";+ access_token;消息=访问令牌:"+ access_token;}别的 {message = "错误:"+ response.error_description + "(" + response.error + ")";}document.getElementById("result").innerHTML = message;};xhr.responseType = 'json';xhr.open(POST", tokenEndpoint, true);xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');xhr.send(新 URLSearchParams({客户端 ID:客户端 ID,code_verifier: window.sessionStorage.getItem("code_verifier"),授权类型:授权代码",redirect_uri: location.href.replace(location.search, ''),代码:代码}));}}document.getElementById("startButton").onclick = function() {var codeVerifier = generateRandomString(64);generateCodeChallenge(codeVerifier).then(function(codeChallenge) {window.sessionStorage.setItem(code_verifier", codeVerifier);var redirectUri = window.location.href.split('?')[0];var args = new URLSearchParams({响应类型:代码",客户端 ID:客户端 ID,code_challenge_method:S256",代码挑战:代码挑战,redirect_uri:redirectUri});window.location = authorizeEndpoint + "/?";+ 参数;});}异步函数 generateCodeChallenge(codeVerifier) {vardigest = await crypto.subtle.digest(SHA-256",new TextEncoder().encode(codeVerifier));return btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')}函数 generateRandomString(length) {var text = "";var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for (var i = 0; i < length; i++) {text += possible.charAt(Math.floor(Math.random() * possible.length));}返回文本;}var vueApp = new Vue({el: '#app',数据 () {返回 {信息:空}},方法: {callApi1:函数(事件){console.log(调用 API 1");公理.get('https://httpbin.org/bearer').then(response => (this.info = response));},callApi2:函数(事件){console.log(调用 API 2");公理.get('https://httpbin.org/headers').then(response => (this.info = response));}}});</html>

I have a front end VueJS application running on port 8080 and a NodeJS server on port 3000. Now I need to integrate a secondary app whose API I need to access on a button click from my VueJS application. My current server architecture is as follows, I need to know whether I need to create a new server for the Authorization server or I can integrate with port 3000?

If I need to create a new server Authorization server, how do I add it? what are the settings. The problem what I faced is, I tried integrating the Authorization server with my backend server with port 3000, I was able to use the resource server, however I was able to call add API call only through redirect url as shown below (OAuth.js):

router.get('/oauth', async (req: Request, res: Response)=>{
    oAuthSession = new OAuth(config.oauthRequestTokenUri, config.oauthAccessTokenUri, config.clientKey, config.clientSecret,
        config.oAuthVersion, config.authorizeCallbackUri, config.oAuthSignatureMethod, config.oAuthNonceSize, config.oAuthCustomHeaders);

      ......

}


    router.get('/callback', async (req: Request, res: Response)=>{
        tokens.verifier = req.query.oauth_verifier;
    
        l('----- Callback - Verifier Received -----');
        l(JSON.stringify(tokens, null, 2));
    
        l('----- Requesting Access Token and Secret -----');
    
        oAuthSession.getOAuthAccessToken(tokens.requestToken, tokens.requestTokenSecret, tokens.verifier, function (error, token, secret, results) {
            tokens.accessToken = token;
            tokens.accessTokenSecret = secret;
    
            l('----- Access Token and Secret Received -----');
            l('StatusCode => ' + results.statusCode);
            l(JSON.stringify(tokens, null, 2));
    
            oAuthSession.get(config.platformBaseUri, tokens.accessToken, tokens.accessTokenSecret, function (error, responseData, result) {
              l('StatusCode => ' + result.statusCode);
    
    
              l('----- Ready to do OAuth authenticated calls now-----');
              res.redirect(`http://localhost:3000/auth/add?accessToken=${tokens.accessToken}&accessTokenSecret=${tokens.accessTokenSecret}`)
              res.end();

But when I tried calling the API call from the frontend VueJS, the API call doesn't get called. It triggers only thorugh the redirect URL shown in the above code. How should the API call be used from the frontend, should there be any configuration changes done for the new server (Authorization server) if added. I am newbie to this domain, if there is any lack of understanding in my problem, please let me know, I will try my best to clarify it.

解决方案

Architecturally speaking, you should have:

  • 1 OAuth server
  • 1 front-end
  • 2 APIs
  • 1 OAuth client (If both of your APIs will accept a token from you OAuth server, likely)

The front-end is the OAuth client.

So, your VueJS client should:

  1. Get a token from the OAuth server
  2. Call API 1
  3. In the button handler (or whatever), call the API 2

Both APIs should validate the token presented to them to ensure that they came from the OAuth server and are trustworthy.

Here's an example (sans-OAuth server and sans-API) that shows how the client/front-end will work. It's derived from this example that has more info.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Public Client Sample</title>
  </head>
  <body>
    <h1>Public Client Sample</h1>
    <button id="startButton">Start OAuth Flow</button>
    <span id="result"></span>
    <div id="app">      
      <button v-on:click="callApi1">Call API 1</button>
      <button v-on:click="callApi2">Call API 2</button>
      {{ info }}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        const authorizeEndpoint = "https://localhost:8443/dev/oauth/authorize";
        const tokenEndpoint = "https://localhost:8443/dev/oauth/token";
        const clientId = "public_client";
        var access_token;

        if (window.location.search && window.location.search.length > 0) {
            var args = new URLSearchParams(window.location.search);
            var code = args.get("code");

            if (code) {
                var xhr = new XMLHttpRequest();

                xhr.onload = function() {
                    var response = xhr.response;
                    var message;

                    if (xhr.status == 200) {
                        var access_token = response.access_token;
                        axios.defaults.headers.common["Authorization"] = "Bearer " + access_token;
                        message = "Access Token: " + access_token;
                    }
                    else {
                        message = "Error: " + response.error_description + " (" + response.error + ")";
                    }

                    document.getElementById("result").innerHTML = message;
                };
                xhr.responseType = 'json';
                xhr.open("POST", tokenEndpoint, true);
                xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                xhr.send(new URLSearchParams({
                    client_id: clientId,
                    code_verifier: window.sessionStorage.getItem("code_verifier"),
                    grant_type: "authorization_code",
                    redirect_uri: location.href.replace(location.search, ''),
                    code: code
                }));
            }
        }

        document.getElementById("startButton").onclick = function() {
            var codeVerifier = generateRandomString(64);

            generateCodeChallenge(codeVerifier).then(function(codeChallenge) {
                window.sessionStorage.setItem("code_verifier", codeVerifier);

                var redirectUri = window.location.href.split('?')[0];
                var args = new URLSearchParams({
                    response_type: "code",
                    client_id: clientId,
                    code_challenge_method: "S256",
                    code_challenge: codeChallenge,
                    redirect_uri: redirectUri
                });
                window.location = authorizeEndpoint + "/?" + args;
            });
        }

        async function generateCodeChallenge(codeVerifier) {
            var digest = await crypto.subtle.digest("SHA-256",
                new TextEncoder().encode(codeVerifier));

            return btoa(String.fromCharCode(...new Uint8Array(digest)))
                .replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
        }

        function generateRandomString(length) {
            var text = "";
            var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

            for (var i = 0; i < length; i++) {
                text += possible.charAt(Math.floor(Math.random() * possible.length));
            }

            return text;
        }

        var vueApp = new Vue({
          el: '#app',
          data () {
            return {
              info: null
            }
          },
          methods: {
            callApi1: function(event) {
                console.log("Call API 1");
                axios
                  .get('https://httpbin.org/bearer')
                  .then(response => (this.info = response));
            },
            callApi2: function(event) {
                console.log("Call API 2");
                axios
                  .get('https://httpbin.org/headers')
                  .then(response => (this.info = response));
            }
          }
        });
    </script>    
  </body>
</html>

这篇关于需要协助在 VueJS 应用程序中集成 OAuth的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆