php—使用信号量修复并发问题

ncgqoxb0  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(375)

我最近问了一个问题:请链接此处,了解在autodesk forge web应用程序中存储刷新令牌的最佳方法。我当前将刷新令牌存储在一个只有一行和一列的sql数据库中,其中包含刷新令牌。关于令牌的步骤如下:
当用户登录时,会调用get方法从数据库中检索最新的令牌。php只是连接到sqldb并从表中检索行。获取方法代码:

function getRefreshToken() {
    $.get("returndata.php",
        function(response) {
            var res = JSON.parse(response);
           console.log(response);
            console.log(res);
            refreshToken = res[0].Value;
           // console.log(refreshToken);
            useRefresh();
           // console.log(response.value);
            //var times = response.times;
        }, 
    );  
}

令牌将被返回并用于获取用户的访问令牌。
检索访问令牌时,它会附带一个刷新令牌,该刷新令牌随后会与上一个刷新令牌保存在sql数据库的同一行中。savesettings.php只需连接到数据库并使用新的刷新标记更新单行。存储刷新令牌的post方法的代码:

function saveRefreshToken() {

    $.post("savesettings.php",
    {
       Value: refreshToken,
    },
    function(data, status){
    console.log(data);
  });

}

在大多数情况下,这个方法工作得很好,但是有几次它被窃听了。我认为这是由于并发问题。如果两个用户在非常相似的时间访问数据库,数据可能会损坏或给出错误的数据。要解决这个问题,我知道我需要使用一个信号量,以便其他请求等到第一个请求完成后再执行。如何使用信号量来实现这一点?任何帮助将不胜感激,因为我在这个问题上非常坚持。谢谢。干杯!!
编辑

function getToken(){
    $.ajax({
    method: 'POST',
    url: 'https://developer.api.autodesk.com/authentication/v1/gettoken',
    headers: {
        'Content-Type':'application/x-www-form-urlencoded'
    },
    data:'client_id=xxxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxx&grant_type=authorization_code&code=' + code + '&redirect_uri=xxxxxxxxxxxxxxxxxxxxxx',

    success:function(response){
       // console.log(response);
        access_token = response.access_token;
        console.log(access_token);
        console.log(response);
        refreshToken = response.refresh_token;
        saveRefreshToken()

    }
})
}

function useRefresh(){
$.ajax({
    method:'POST',
    url: 'https://developer.api.autodesk.com/authentication/v1/refreshtoken',
    headers: {
        'Content-Type':'application/x-www-form-urlencoded'
    },
    data:'client_id=xxxxxxxxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxx&grant_type=refresh_token&refresh_token='+refreshToken+'&scope=data:read',
success:function(response){
    console.log(response);
    refreshToken = response.refresh_token;
    //console.log(refreshToken);
    access_token = response.access_token;
    saveRefreshToken();
}
})
}
jum4pzuy

jum4pzuy1#

evert仅与mysql racing问题相关时是正确的。在您的情况下,您还调用另一个服务器来获取访问令牌;这意味着我们需要在刷新时锁定表以进行读/写操作。
我在这里写了一个小例子,它能解决这个问题。然而,正如evert所说,如果您选择信号量方法,它将只在处理http请求的单个服务器上工作。如果您正在进行负载平衡,我们需要使用mysql/redis锁方法。我说redis,因为在这个主题上它比mysql更好。
该示例还将向您展示在forge应用程序中获取令牌的正确方法。在上面的代码中,我注意到您正在使用$.ajax()代码,这意味着您在oauth服务器上从html页面(在客户端?)执行http调用—这样做会使您面临高安全性问题,您正在泄漏访问令牌和clientid/密钥。任何人都可以在你不知情的情况下窃取你的客户ID/机密并开始使用你的帐户。
您应该颁发2个访问令牌,一个具有最低权限的公共令牌(此令牌将仅用于查看器)。具有附加权限的第二个令牌将保留在服务器上,并且永远不会向任何客户端应用程序公开。
该示例执行两个简单操作:
使用公共标记在查看器中显示模型
使用内部标记列出bucket或文件夹中的模型
该示例还显示了一个两条腿的流和一个三条腿的代码流。虽然理论上两者应该以相同的方式工作,但有一个重要的区别需要知道。
您可以随时生成任意数量的2条腿的令牌。这意味着您将始终获得有效的令牌,即使您在同一时刻多次使用令牌。实际上,不刷新令牌,每次都创建一个新的令牌,这样做不会使以前生成的令牌失效。这个示例有点懒惰,只要在需要时立即获取token,而不必担心服务器处理的http请求。
虽然您也可以生成所需的任意多个3条腿的令牌(代码流),但每次创建新令牌时都需要登录,这会限制您的使用。但是,当您创建一个访问令牌时,它会附带一个刷新令牌,允许您在每次需要时续订访问令牌。但是,刷新令牌有3个注意事项:
刷新令牌仅在14天内有效,因此您需要至少每14天刷新一次令牌。
第一次创建令牌时,需要提供可能需要的所有作用域。刷新令牌时,可以降级作用域,但永远不能添加新作用域。
每当您使用刷新令牌时,此令牌将丢失,但您将获得一个新令牌。最后一个令牌是您接下来需要使用的令牌。
例如,要使用2legged版本,只需访问服务器的根目录即可http://localhost/
要使用3条腿的版本,请转到http://localhost/login 要创建新的令牌对,请转到http://localhost/www/bim360.html
还有一个小测试示例,它将在服务器上同时激发5个http请求。我将我的apache示例限制为一次处理2个请求,这是为了验证在续订令牌时,所有请求都没有相互竞争,这将使您的令牌/刷新令牌不同步。
自述文件应该有足够的细节来部署示例并浏览代码。

h79rfbju

h79rfbju2#

如果在php和mysql中遇到并发问题,那么信号量不是解决这个问题的合适级别。例如,如果您想运行第二台服务器来处理php请求,该怎么办。
正确的处理方法是在数据库中。如果损坏发生在单个请求期间,则可能是您的查询错误,或者您需要使用事务或锁。

相关问题