APP登陆以及OAUTH2全过程记录(一)

2017-08-30 14:27:06

    我发现,在app端中使用passport时,混混沌沌,如同在梦里一般。

    所以我决定 老老实实的把全过程好好的记录一下,期间资料确实少,只能自己研究,可能会走些弯路,做些没有必要的事情,君不见,当年我曾写过大约几十行代码,后来发现,有内置的方法,一行解决。但现在我也顾不了许多了,先上吧,嘲笑自己那是以后的事情啦。

    由于服务端构建工作大致已经完成了,具体链接可查看

记录一下实现laravel Passport 认证的过程(服务端篇)

    所以目前,我需要实现APP端的PASSPORT认证过程。

    先梳理一下流程,当APP端使用短信验证码登陆的时候,服务端需要把相应的token返回给APP,APP端把token存储以后,以后在请求头带上此token,这样服务端在验证此token合法后,用户将会被认证身份,也可以赋予相应的权限。

    不过我现在面临两个难点,我GOOGLE了好一会,发现在得到TOKEN的过程中,用户必须以用户名+密码的方法授权的这种组合,但是我的构想是手机号+手机验证码这个流程来完成认证,并发放TOKEN的需求。

    还有就是关于官网所说的客户端凭证授权令牌这一块,我使用了官方提供的此代码,

$guzzle = new GuzzleHttp\Client;

$response = $guzzle->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'client_credentials',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => 'your-scope',
    ],
]);

echo json_decode((string) $response->getBody(), true);

    发现,虽然可以获取到token,但此token好像根本不起作用,无法得到服务端的认可。搜索以后未果,没办法,还是只能回到如下方法

Route::get('/callback', function (Request $request) {
    $http = new GuzzleHttp\Client;

    $response = $http->post('http://your-app.com/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => 'client-id',
            'client_secret' => 'client-secret',
            'redirect_uri' => 'http://example.com/callback',
            'code' => $request->code,
        ],
    ]);

    return json_decode((string) $response->getBody(), true);
});

    此方法确实能得到被服务端认可的token, 但是需要传递关键参数,CODE。而此code官方并没有提到如何得到。没有办法,只能自己研究一番。

    先从官方提供的VUE模板入手,我们得先看看它的client_id,client_secret,以及redirect_uri是怎么生成,怎么入库的。图片如下:

    image.png

    我们通过抓包发现,

image.png

    其请求地址为/oauth/clients,提交的post参数如下

{"errors":[],"name":"nosay","redirect":"https://www.muzilong.cn/"}

我们追踪到相应的控制器中,找到了对应的入库代码

public function store(Request $request)
    {
        $this->validation->make($request->all(), [
            'name' => 'required|max:255',
            'redirect' => 'required|url',
        ])->validate();
        

        return $this->clients->create(
            $request->user('admin')->getKey(), $request->name, $request->redirect
        )->makeVisible('secret');
    }

    当然,因为我是后台授予认证,所以把$request->user()->getKey()改为$request->user('admin')->getKey();了, 这个在前文中有提到。

    看了一下,无非就是一个数据库插入的操作,其中secret为一个随机生成的40位字符串。

    这样的话,我们在APP中的第一步,可以判断此用户是否已经生成了相应的记录,期间我注意到,相应的表oauth_clients中,存在一个revoked字段,当从前台删除的时候,此字段的值就直接变成1,其实并不是传统意义上的删除,是一个伪删除。

    所以我们要判断此用户是否已经存在记录,并且revoked字段为0。如果查询不到的话,我们插入相应的数据,如果查询到了的话,直接使用此secret即可。


    创建一个repository,主要获取秘钥(secret),授权码(code),令牌(access_token),等等。

    先上一个获取secret的相关方法,

public function getMyOauthSecretById($id)
    {
        $clientRepository = new ClientRepository();
        $clentInfo = $clientRepository->getActiveByUser($id);
        $data = [];
        if(is_object($clentInfo))
        {
            $data['secret'] = $clentInfo->secret;
            $data['id'] = $clentInfo->id;
        }else{
            $clentInfo = $clientRepository->create(
                $id, "nosay", "https://www.muzilong.cn/"
            )->makeVisible('secret');
            $data['secret'] = $clentInfo->secret;
            $data['id'] = $clentInfo->id;
        }
        return $data;
    }

    接下来我们需要得到授权码