Angular 应用授权和 Zoho CRM 的问题

Posted

技术标签:

【中文标题】Angular 应用授权和 Zoho CRM 的问题【英文标题】:Issue with Angular App Authorization and Zoho CRM 【发布时间】:2022-01-15 00:47:07 【问题描述】:

我正在寻找一种方法来构建一个 Angular 应用程序,该应用程序可以发送请求并接收来自 Zoho CRM 的响应。我尝试了 Zoho CRM 文档中记录的所有可能性,但对我没有任何帮助:

我遵循的步骤:

    我在https://api-console.zoho.com/ 上注册了应用程序,为基于客户端、基于服务器、自客户端。

    我按照文档https://www.zoho.com/accounts/protocol/oauth/web-server-applications.html 处理每种情况(客户端、服务器、自身)。

    请求授权请求以获取代码并生成令牌以访问 CRM API https://accounts.zoho.com/oauth/v2/auth?response_type=code&client_id=1000.GMB0YULZHJK411284S8I5GZ4CHUEX0&scope=AaaServer.profile.Read&redirect_uri=https://www.zylker.com/oauthredirect&prompt=consent

    我在重定向的 URL 中获得了代码https://www.zylker.com/oauthredirect?code=1000.9c3a2a6a5362125efc9f7666224313b6.d44f4b5b63e71fc682cdf20c771efead&location=us

    从应用程序生成令牌失败,即使在使用上面 URL 中生成的代码从邮递员那里获取令牌之后,任何请求也是如此。

并且总是遇到 CORS 政策问题,即使我在请求标头中添加了 "Access-Control-Allow-Origin":"*" 或将 * 替换为我的来源:

【问题讨论】:

【参考方案1】:

    运行您的项目,您应该被重定向到 zoho 以授予您访问权限。

    您还应该被重定向到您在 zoho 控制台中设置的重定向 URL,请添加以下内容以将参数保存到您的本地存储,redirect.component.ts

import  Component, OnInit  from '@angular/core';

@Component(
    selector: 'app-redirect',
    templateUrl: './redirect.component.html',
    styleUrls: ['./redirect.component.css']
)
export class RedirectComponent implements OnInit 
    constructor()  

    ngOnInit(): void 
        this.setAccessToken();
    

    getPropertiesFromURL() 
        var props: any = ;
        var propertyString = window.location.hash || window.location.search;

        if (propertyString && typeof propertyString === 'string') 
            propertyString = propertyString.slice(1);
            if (propertyString) 
                propertyString
                    .split('&')
                    .forEach(function (prop) 
                        var key = prop.split('=')[0], value = prop.split('=')[1];
                        props[key] = value;
                    );
            
        
        return props;
    
    // set the access token and grant access to localstorage
    setAccessToken() 
        var hashProps = this.getPropertiesFromURL();
        console.log("hashprops", hashProps)
        if (hashProps) 

            for (var k in hashProps) 
                if (hashProps.hasOwnProperty(k)) 
                    var key = (k === 'access_toke' || k === 'access_token') ? 'access_token' : k;
                    var value = (k === 'api_domain') ? decodeURIComponent(hashProps[k]) : hashProps[k];
                    localStorage.setItem(key, value);
                
            
        
        setTimeout(function ()  window.close(); , 0);
    

    现在您可以在 app.component.ts 处添加以下内容以获得响应:

var input = 'module' : 'Leads';

    ZCRM.API.RECORDS.get(input).then(function(resp)
            var data = JSON.parse(resp).data;
      
     
        console.log("data", data)
);
    在第 3 点我已经在 377 到 387 行和 84 行稍微修改了 SDK 以适应我的情况它应该也适合您,我将发布原始 SDK,您也可以对其进行配置。

原始 SDK:

var libBase, headers, HTTP_METHODS, version;
version = 2;
HTTP_METHODS = 
    GET : "GET",//No I18N
    POST : "POST",//No I18N
    PUT : "PUT",//No I18N
    DELETE : "DELETE"//No I18N
;

function promiseResponse(request) 
    return new Promise(function (resolve, reject) 
        var body, baseUrl, xhr, i, formData;
        libBase = localStorage.api_domain+"/crm/v"+version+"/";
        baseUrl = libBase + request.url;

        var token = ZCRM.API.AUTH.getAccess();
        if(token == null)
                return resolve('');   // in case of no ticket, returns empty json
        

        if (request.params)
        
            baseUrl = baseUrl + '?' + request.params;
        

        xhr = new XMLHttpRequest();
        xhr.withCredentials = true
        xhr.open(request.type, baseUrl);
        xhr.setRequestHeader("Authorization", "Zoho-oauthtoken "+token)
        for (i in headers)
        
            xhr.setRequestHeader(i, headers[i]);
        

        if (request.download_file)
            xhr.responseType = "blob";//No I18N
        

        if (request.x_file_content) 
            formData = new FormData();
            formData.append('file', request.x_file_content);//No I18N
            xhr.send(formData);
        
        else
            body = request.body || null;
            xhr.send(body);
        

        xhr.onreadystatechange = function() 
                if(xhr.readyState == 4)
                    if (xhr.status == 204)
                    
                        var respObj = 
                            "message" : "no data", //No I18N
                            "status_code" : "204" //No I18N
                        
                        resolve(JSON.stringify(respObj));
                    
                    else
                    
                        if (request.download_file)
                            var filename;
                            var disposition = xhr.getResponseHeader("Content-Disposition");//No I18N
                            if (disposition && disposition.indexOf('attachment') !== -1) 
                                var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                                var matches = filenameRegex.exec(disposition);
                                if (matches != null && matches[1]) 
                                  filename = matches[1].replace(/['"]/g, '');
                                    filename = filename.replace('UTF-8','');
                                
                            
                            var blob = xhr.response;
                            var url = URL.createObjectURL(blob);
                            var ttt = document.createElement('a');
                            ttt.href = url;
                            ttt.download = filename;
                            ttt.click();
                        
                        else
                            resolve(xhr.response);
                        
                    
                
            
    )
;
function createParams(parameters)

    var params, key;
    for (key in parameters)
    
        if (parameters.hasOwnProperty(key)) 
            if (params)
            
                params = params + key + '=' + parameters[key] + '&';
            
            else
            
                params = key + '=' + parameters[key] + '&';
            
        
    

    return params;
;
function constructRequestDetails(input, url, type, isModuleParam)

    var requestDetails = ;

    requestDetails.type = type;

    if (input != undefined)
    
        if (input.id)
        
            url = url.replace("id", input.id);
//                        url = url + "/" + input.id;
        
        else
        
            url = url.replace("/id", "");
        
        if (input.params)
        
            requestDetails.params = createParams(input.params) + (input.module && isModuleParam ? "module=" + input.module : "");//No I18N
        
        if (!requestDetails.params && isModuleParam)
        
            requestDetails.params = "module=" + input.module;//No I18N
        
        if (input.body && (type == HTTP_METHODS.POST || type == HTTP_METHODS.PUT))
        
            requestDetails.body = JSON.stringify(input.body);
        
        if (input.x_file_content)
        
            requestDetails.x_file_content = input.x_file_content;
        
        if (input.download_file)
        
            requestDetails.download_file = input.download_file;
        
    
    requestDetails.url = url;

    return requestDetails;
;
function getParameterByName(name, url)

    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
    var results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));

function sdk()

   return 
       initialize : function (configuration)
       
           if(document.getElementById("zes_client_scope") == null)
                var elem = document.createElement('div');
                elem.setAttribute("data-scope",configuration.scopes);
                elem.setAttribute("data-clientid",configuration.client_id);
                elem.setAttribute("data-accounts-url",configuration.accounts_url);
                elem.setAttribute("id","zes_client_scope");

                document.body.appendChild(elem);
            

            var input = ;
               ZCRM.API.USERS.get(input).then(function(resp)
                );
       
   

function actions()


    return 
        convert : function (input)
        
            return promiseResponse(constructRequestDetails(input, "Leads/id/actions/convert", HTTP_METHODS.POST, false));//No I18N
        
    

function attachments()


    return 
        uploadFile : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module+ "/id/Attachments", HTTP_METHODS.POST, false));//No I18N
        ,
        deleteFile : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module+ "/id/Attachments/"+input.relatedId, HTTP_METHODS.DELETE, false));//No I18N
        ,
        downloadFile : function (input)
        
            input.download_file = true;
            return promiseResponse(constructRequestDetails(input, input.module+ "/id/Attachments/"+input.relatedId, HTTP_METHODS.GET, false));//No I18N
        ,
        uploadLink : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module+ "/id/Attachments", HTTP_METHODS.POST, false));//No I18N
        ,
        uploadPhoto : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module+ "/id/photo", HTTP_METHODS.POST, false));//No I18N
        ,
        downloadPhoto : function (input)
        
            input.download_file = true;
            return promiseResponse(constructRequestDetails(input, input.module + "/id/photo", HTTP_METHODS.GET, false));//No I18N
        ,
        deletePhoto : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id/photo", HTTP_METHODS.DELETE, false));//No I18N
        
    


function org()


    return 
        get : function (input)
        
            return promiseResponse(constructRequestDetails(input, "org", HTTP_METHODS.GET, true));//No I18N
        
    


function records()

    
    return 
        get : function(input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.GET, false));//No I18N
        ,
        post : function(input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.POST, false));//No I18N
        ,
        put : function(input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.PUT, false));//No I18N
        ,
        delete : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.DELETE, false));//No I18N
        ,
        getNotes : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id/Notes", HTTP_METHODS.GET, false));//No I18N
        ,
        getRelated : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/id/"+input.relatedModule, HTTP_METHODS.GET, false));//No I18N
        ,
        getAllDeletedRecords : function (input)
        
            if (input.params)
            
                input.params.type = "all";
            
            else
            
                input.params = 
                    "type" : "all"//No I18N
                ;
            

            return promiseResponse(constructRequestDetails(input, input.module + "/deleted", HTTP_METHODS.GET, false));//No I18N
        ,
        getRecycleBinRecords : function (input)
        
            if (input.params)
            
                input.type = "recycle";
            
            else
            
                input.params = 
                    "type" : "recycle"//No I18N
                ;
            

            return promiseResponse(constructRequestDetails(input, input.module + "/deleted", HTTP_METHODS.GET, false));//No I18N
        ,
        getPermanentlyDeletedRecords : function (input)
        
            if (input.params)
            
                input.type = "permanent";
            
            else
            
                input.params = 
                    "type" : "permanent"//No I18N
                ;
            

            return promiseResponse(constructRequestDetails(input, input.module + "/deleted", HTTP_METHODS.GET, false));//No I18N
        ,
        search : function (input)
        
            return promiseResponse(constructRequestDetails(input, input.module + "/search", HTTP_METHODS.GET, false));//No I18N
        
    

function settings()

    
    return 
        getFields : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/fields/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getLayouts : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/layouts/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getCustomViews : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/custom_views/id", HTTP_METHODS.GET, true));//No I18N
        ,
        updateCustomViews : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/custom_views/id", HTTP_METHODS.PUT, true));//No I18N
        ,
        getModules : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/modules" + ((input && input.module) ? "/" + input.module : ""), HTTP_METHODS.GET, false));//No I18N
        ,
        getRoles : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/roles/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getProfiles : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/profiles/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getRelatedLists : function (input)
        
            return promiseResponse(constructRequestDetails(input, "settings/related_lists/id", HTTP_METHODS.GET, true));//No I18N
        
    

function users()

    
    return 
        get : function (input)
        
            return promiseResponse(constructRequestDetails(input, "users/id", HTTP_METHODS.GET, true));//No I18N
        
    

var listener = 0;
function auth()

    return 
        getAccess : function()
            if(listener == 0)
                 window.addEventListener("storage", function(e)
                        if(e.key === 'access_token' && e.oldValue!=e.newValue && e.oldValue == null)
                                location.reload();
                        
                        if(e.key === 'access_token')
                                localStorage.removeItem('__auth_process');
                        
                , false);
                listener = 1;
                if(localStorage.getItem('__auth_process')) localStorage.removeItem('__auth_process'); 
            


            var valueInStore = localStorage.getItem('access_token');
            var token_init = localStorage.getItem('__token_init');
            if(token_init != null && valueInStore != null && Date.now() >= parseInt(token_init)+55*60*1000) // check after 55 mins
                valueInStore = null;
                localStorage.removeItem('access_token');
            
            var auth_process = localStorage.getItem('__auth_process');

            if (valueInStore == null && auth_process == null)
            
                var accountsUrl =document.getElementById("zes_client_scope").getAttribute("data-accounts-url");
                var endPoint = "/oauth/v2/auth";
        var full_grant = localStorage.getItem('full_grant');
        if(full_grant != null && 'true' == full_grant && localStorage.getItem('__token_init') != null)
            endPoint += '/refresh';
        
                var client_id = document.getElementById("zes_client_scope").getAttribute("data-clientid");
                var scope = document.getElementById("zes_client_scope").getAttribute("data-scope");

                var path = window.location.pathname;
                var redirect_url = window.location.origin;
                var pathSplit = path.split('/');
                var length=pathSplit.length
                for (var i=0;i<length-2;i++)
                       redirect_url +=pathSplit[i]+"/";
                
                if(location.hostname=="127.0.0.1" ||location.hostname=="localhost" ||location.hostname=="" )
                    if(length-2 == 0)
                    
                        redirect_url += "/";
                    
                    redirect_url += "app/"
                
                redirect_url = redirect_url + "redirect.html";

                if (client_id && scope)
                    localStorage.setItem('__token_init', Date.now());
                    localStorage.removeItem('access_token');
                    localStorage.setItem('__auth_process', 'true');
                    var popup = window.open(accountsUrl+endPoint+"?scope="+scope+"&client_id="+client_id+"&response_type=token&state=zohocrmclient&redirect_uri="+redirect_url);//,'', 'width:' + window.innerWidth + ',height:' + window.innerHeight);
                        //popup.focus();
                
                else
                    throw 'missing auth params[clientId, redirectUri, scope]';
                
            
            return valueInStore;
        ,
        revokeAccess : function ()
            localStorage.removeItem('crm_access_token');
        
    


    var ZCRM = (function (argument) 
    return 
        API : (function (argument) 
            return
                SDK : new sdk(),
                AUTH : new auth(),
                RECORDS : new records(),
                SETTINGS : new settings(),
                ACTIONS : new actions(),
                USERS : new users(),
                ORG : new org(),
                ATTACHMENTS : new attachments()
            
        )(this),
    init: function(data)
            if(data.constructor === .constructor && data.hasOwnProperty('full_grant') && data['full_grant'] == true)
                localStorage.setItem('full_grant', 'true');
            
        
    
)(this)

我希望这能让别人的生活更轻松,如果有任何机构有更好的解决方案,我很乐意检查一下

【讨论】:

【参考方案2】:
    在https://api-console.zoho.com/ 上注册您的应用,作为基于客户端的应用

    在您的 Angular 应用程序中,创建一个 RedirectComponent 并将其包含在您的 app-routing.module.ts

    在您的资产中创建 zcrmsdk.js 并输入以下代码:

var libBase, headers, HTTP_METHODS, version;
version = 2;
HTTP_METHODS = 
    GET: "GET",//No I18N
    POST: "POST",//No I18N
    PUT: "PUT",//No I18N
    DELETE: "DELETE"//No I18N
;

function promiseResponse(request) 
    return new Promise(function (resolve, reject) 
        var body, baseUrl, xhr, i, formData;
        libBase = localStorage.api_domain + "/crm/v" + version + "/";
        // console.log("libbase", libBase)
        baseUrl = libBase + request.url;

        var token = ZCRM.API.AUTH.getAccess();
        if (token == null) 
            return resolve('');   // in case of no ticket, returns empty json
        

        if (request.params) 
            baseUrl = baseUrl + '?' + request.params;
        

        xhr = new XMLHttpRequest();
        xhr.withCredentials = true
        xhr.open(request.type, baseUrl);
        xhr.setRequestHeader("Authorization", "Zoho-oauthtoken " + token)
        for (i in headers) 
            xhr.setRequestHeader(i, headers[i]);
        

        if (request.download_file) 
            xhr.responseType = "blob";//No I18N
        

        if (request.x_file_content) 
            formData = new FormData();
            formData.append('file', request.x_file_content);//No I18N
            xhr.send(formData);
        
        else 
            body = request.body || null;
            xhr.send(body);
        

        xhr.onreadystatechange = function () 
            if (xhr.readyState == 4) 
                if (xhr.status == 204) 
                    var respObj = 
                        "message": "no data", //No I18N
                        "status_code": "204" //No I18N
                    
                    resolve(JSON.stringify(respObj));
                
                else 
                    if (request.download_file) 
                        var filename;
                        var disposition = xhr.getResponseHeader("Content-Disposition");//No I18N
                        if (disposition && disposition.indexOf('attachment') !== -1) 
                            var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                            var matches = filenameRegex.exec(disposition);
                            if (matches != null && matches[1]) 
                                filename = matches[1].replace(/['"]/g, '');
                                filename = filename.replace('UTF-8', '');
                            
                        
                        var blob = xhr.response;
                        var url = URL.createObjectURL(blob);
                        var ttt = document.createElement('a');
                        ttt.href = url;
                        ttt.download = filename;
                        ttt.click();
                    
                    else 
                        resolve(xhr.response);
                    
                
            
        
    )
;
function createParams(parameters) 
    var params, key;
    for (key in parameters) 
        if (parameters.hasOwnProperty(key)) 
            params = parameters;
        
    
    return params;
;
function constructRequestDetails(input, url, type, isModuleParam) 
    var requestDetails = ;

    requestDetails.type = type;

    if (input != undefined) 
        if (input.id) 
            // console.log("IAM HERE 1");

            url = url.replace("id", input.id);
            //                        url = url + "/" + input.id;
        
        else 
            // console.log("IAM HERE 2");

            url = url.replace("/id", "");
        
        if (input.params) 
            // console.log("IAM HERE1 3", input.params, "then", input.module, "hh", isModuleParam);

            requestDetails.params = createParams(input.params) + (input.module && isModuleParam ? "module=" + input.module : "");//No I18N
        
        if (!requestDetails.params && isModuleParam) 
            // console.log("IAM HERE 4");
            requestDetails.params = "module=" + input.module;//No I18N
        
        if (input.body && (type == HTTP_METHODS.POST || type == HTTP_METHODS.PUT)) 
            // console.log("IAM HERE 5");

            requestDetails.body = JSON.stringify(input.body);
        
        if (input.x_file_content) 
            // console.log("IAM HERE 6");

            requestDetails.x_file_content = input.x_file_content;
        
        if (input.download_file) 
            requestDetails.download_file = input.download_file;
        
    
    requestDetails.url = url;

    return requestDetails;
;
function getParameterByName(name, url) 
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
    var results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));

function sdk() 
    return 
        initialize: function (configuration) 
            if (document.getElementById("zes_client_scope") == null) 
                var elem = document.createElement('div');
                elem.setAttribute("data-scope", configuration.scopes);
                elem.setAttribute("data-clientid", configuration.clientId);
                elem.setAttribute("data-accounts-url", configuration.accountUrl);
                elem.setAttribute("id", "zes_client_scope");

                document.body.appendChild(elem);
            
            // console.log("initialize", document.body)

            var input = ;
            ZCRM.API.USERS.get(input).then(function (resp) 
            );
        
    

function actions() 

    return 
        convert: function (input) 
            return promiseResponse(constructRequestDetails(input, "Leads/id/actions/convert", HTTP_METHODS.POST, false));//No I18N
        
    

function attachments() 

    return 
        uploadFile: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/Attachments", HTTP_METHODS.POST, false));//No I18N
        ,
        deleteFile: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/Attachments/" + input.relatedId, HTTP_METHODS.DELETE, false));//No I18N
        ,
        downloadFile: function (input) 
            input.download_file = true;
            return promiseResponse(constructRequestDetails(input, input.module + "/id/Attachments/" + input.relatedId, HTTP_METHODS.GET, false));//No I18N
        ,
        uploadLink: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/Attachments", HTTP_METHODS.POST, false));//No I18N
        ,
        uploadPhoto: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/photo", HTTP_METHODS.POST, false));//No I18N
        ,
        downloadPhoto: function (input) 
            input.download_file = true;
            return promiseResponse(constructRequestDetails(input, input.module + "/id/photo", HTTP_METHODS.GET, false));//No I18N
        ,
        deletePhoto: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/photo", HTTP_METHODS.DELETE, false));//No I18N
        
    


function org() 

    return 
        get: function (input) 
            return promiseResponse(constructRequestDetails(input, "org", HTTP_METHODS.GET, true));//No I18N
        
    


function records() 

    return 
        get: function (input) 
            // console.log("zcrm", input);
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.GET, false));//No I18N
        ,
        post: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.POST, false));//No I18N
        ,
        put: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.PUT, false));//No I18N
        ,
        delete: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id", HTTP_METHODS.DELETE, false));//No I18N
        ,
        getNotes: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/Notes", HTTP_METHODS.GET, false));//No I18N
        ,
        getRelated: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/id/" + input.relatedModule, HTTP_METHODS.GET, false));//No I18N
        ,
        getAllDeletedRecords: function (input) 
            if (input.params) 
                input.params.type = "all";
            
            else 
                input.params = 
                    "type": "all"//No I18N
                ;
            

            return promiseResponse(constructRequestDetails(input, input.module + "/deleted", HTTP_METHODS.GET, false));//No I18N
        ,
        getRecycleBinRecords: function (input) 
            if (input.params) 
                input.type = "recycle";
            
            else 
                input.params = 
                    "type": "recycle"//No I18N
                ;
            

            return promiseResponse(constructRequestDetails(input, input.module + "/deleted", HTTP_METHODS.GET, false));//No I18N
        ,
        getPermanentlyDeletedRecords: function (input) 
            if (input.params) 
                input.type = "permanent";
            
            else 
                input.params = 
                    "type": "permanent"//No I18N
                ;
            

            return promiseResponse(constructRequestDetails(input, input.module + "/deleted", HTTP_METHODS.GET, false));//No I18N
        ,
        search: function (input) 
            return promiseResponse(constructRequestDetails(input, input.module + "/search", HTTP_METHODS.GET, false));//No I18N
        
    

function settings() 

    return 
        getFields: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/fields/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getLayouts: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/layouts/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getCustomViews: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/custom_views/id", HTTP_METHODS.GET, true));//No I18N
        ,
        updateCustomViews: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/custom_views/id", HTTP_METHODS.PUT, true));//No I18N
        ,
        getModules: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/modules" + ((input && input.module) ? "/" + input.module : ""), HTTP_METHODS.GET, false));//No I18N
        ,
        getRoles: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/roles/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getProfiles: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/profiles/id", HTTP_METHODS.GET, true));//No I18N
        ,
        getRelatedLists: function (input) 
            return promiseResponse(constructRequestDetails(input, "settings/related_lists/id", HTTP_METHODS.GET, true));//No I18N
        
    

function users() 

    return 
        get: function (input) 
            return promiseResponse(constructRequestDetails(input, "users/id", HTTP_METHODS.GET, true));//No I18N
        
    

var listener = 0;
function auth() 
    return 
        getAccess: function () 
            // console.log("inside auth");
            if (listener == 0) 
                // console.log("inside auth 1");

                window.addEventListener("storage", function (e) 
                    if (e.key === 'access_token' && e.oldValue != e.newValue && e.oldValue == null) 

                        location.reload();
                    
                    if (e.key === 'access_token') 
                        localStorage.removeItem('__auth_process');
                    
                , false);
                listener = 1;
                if (localStorage.getItem('__auth_process')) 
                    // console.log("inside auth 2", localStorage.getItem('__auth_process'));

                    localStorage.removeItem('__auth_process');
                
            

            var valueInStore = localStorage.getItem('access_token');
            // console.log("inside auth 3", valueInStore);

            var token_init = localStorage.getItem('__token_init');
            // console.log("inside auth 4", token_init);

            if (token_init != null && valueInStore != null && Date.now() >= parseInt(token_init) + 55 * 60 * 1000)  // check after 55 mins
                // console.log("inside auth 5");
                valueInStore = null;
                localStorage.removeItem('access_token');
            
            var auth_process = localStorage.getItem('__auth_process');
            // console.log("inside auth 6", auth_process);
            if (valueInStore == null && auth_process == null) 
                // console.log("inside auth 7");
                var accountsUrl = document.getElementById("zes_client_scope").getAttribute("data-accounts-url");
                // console.log("inside auth 8", accountsUrl);
                var endPoint = "/oauth/v2/auth";
                var full_grant = localStorage.getItem('full_grant');
                // console.log("inside auth 9", full_grant);
                if (full_grant != null && 'true' == full_grant && localStorage.getItem('__token_init') != null) 
                    // console.log("inside auth 10");

                    endPoint += '/refresh';
                
                var client_id = document.getElementById("zes_client_scope").getAttribute("data-clientid");
                var scope = document.getElementById("zes_client_scope").getAttribute("data-scope");
                // console.log("inside auth 10", client_id, scope);

                var path = window.location.pathname;
                // console.log("inside auth 11", path);
                // console.log(location.hostname)

                var redirect_url = window.location.origin;
                // console.log("inside auth 12", redirect_url);
                var pathSplit = path.split('/');
                var length = pathSplit.length
                for (var i = 0; i < length - 2; i++) 
                    redirect_url += pathSplit[i] + "/";
                
                if (location.hostname == "127.0.0.1" || location.hostname == "") 
                    if (length - 2 == 0) 
                        redirect_url += "/";
                    
                    redirect_url += "app/"
                
                // if ( location.hostname == "localhost" )


                // 
                redirect_url = redirect_url + "/redirect";
                // console.log("rediret", redirect_url);
                if (client_id && scope) 
                    // console.log("inside auth 13", valueInStore)

                    localStorage.setItem('__token_init', Date.now());
                    localStorage.removeItem('access_token');
                    localStorage.setItem('__auth_process', 'true');
                    // var popup = 
                    window.open(accountsUrl + endPoint + "?scope=" + scope + "&client_id=" + client_id + "&response_type=token&state=zohocrmclient&redirect_uri=" + redirect_url);//,'', 'width:' + window.innerWidth + ',height:' + window.innerHeight);
                    // popup.focus();
                
                else 
                    throw 'missing auth params[clientId, redirectUri, scope]';
                
            

            return valueInStore;
        ,
        revokeAccess: function () 
            localStorage.removeItem('crm_access_token');
        
    


var ZCRM = (function (argument) 
    return 
        API: (function (argument) 
            return 
                SDK: new sdk(),
                AUTH: new auth(),
                RECORDS: new records(),
                SETTINGS: new settings(),
                ACTIONS: new actions(),
                USERS: new users(),
                ORG: new org(),
                ATTACHMENTS: new attachments()
            
        )(this),
        init: function (data) 
            if (data.constructor === .constructor && data.hasOwnProperty('full_grant') && data['full_grant'] == true) 
                localStorage.setItem('full_grant', 'true');
            
        
    
)(this)

    在您的资产中包含 Zoho CRM SDK 并将其添加到 index.html&lt;script src="/assets/js/zcrmsdk.js"&gt;&lt;/script&gt;

    在您的根路径中创建一个 globals.d.ts 并声明 SDK:

    declare var ZCRM : any;

    现在您可以访问项目中的 SDK。

    在您的 app.component.ts 中,您需要在 ngOnInit 处使用正确的配置初始化 SDK:

var configuration = ;
configuration.client_id = CLIENT_ID;
configuration.scopes = SCOPES;
configuration.accounts_url = ACCOUNTS_URL;
ZCRM.API.SDK.initialize(configuration);

继续下一个答案

【讨论】:

以上是关于Angular 应用授权和 Zoho CRM 的问题的主要内容,如果未能解决你的问题,请参考以下文章

Twilio 传入的短信在 Zoho CRM 中不起作用

使用http电话登录Zoho CRM

如何使用 php 代码将 ZOHO CRM 与 Zapier 连接?

以CSV格式备份ZOHO CRM中的所有表

Zoho CRM API to Power BI Connector

如何在 zoho crm 中将沙盒编辑代码部署到生产环境