自己动手:实现OAuth2.0

2018年4月11日 0 作者 筱枫

前段时间写了篇文章关于如何使用laravel的oauth2.0功能,现在突然有些手痒,索性自己来实现一个玩具,也好更加了解oauth

阅读本文需要如下技能:

PHP:一般

OAuth:一般

Redis:初学

HTML:初学

如果对oauth不熟悉,建议阅读阮一峰先生的文章:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

首先,准备一个最简单的文件,index.php,然后里面只要能够登陆与已已登录验证的功能就行,这是我的代码,超级简陋,但是能用

if (isset($_GET['action']) && $_GET['action'] === 'login')
    setcookie('isLogined', 'true', 0, "/");

$msg = isset($_COOKIE['isLogined']) && $_COOKIE['isLogined'] === 'true'
    ? '已登陆' : '未登录';

if (isset($_GET['token']) && $_GET['token'] === $redis->get('token')) 
    $msg = '这是经过验证后的数据,绝密!';

echo "
           $msg
           <a href="index.php?action=login">登陆</a> 
";

ok,现在这是一个最基本的界面

下面开始实现让用户点击授权的界面

这是我的代码

authorize.php

 
$redis = new Redis();
$redis-&gt;connect('127.0.0.1', '6379');

$code = random_int(10000, 20000);
$redis-&gt;set('code', $code, 60);

$redirectUrl = $_GET['redirectUrl'];

echo "
申请权限,是否同意?
           <a href="$redirectUrl?code=$code">同意</a>
           <a href="$redirectUrl?code=">拒绝</a> 
";

东西看上去有点多,不过并不复杂,这里采用了redis存储中途要用到的code,并将过期时间设置为60秒
打开这个界面是这个样子的

ok,没有问题,如果用户点击同意,那么code将被会传进客户端的redirectUrl中,否则就不会传递
由于这个页面是服务器显示出来的,所以基本不用担心非用户操作
下面来编写客户端的回调处理,这个回调需要完成用code去服务器换取token并存储的功能
代码如下:

callback.php

$errorMsg = '';

if (!isset($_GET['code']) || $_GET['code'] === '')
    $errorMsg = '你拒绝了权限申请';
else
{
    $url = "http://192.168.100.104/token.php?" . http_build_query(['code' => $_GET['code']]);

    // 向后台服务器用code换取token
    $http = curl_init($url);
    curl_setopt($http, CURLOPT_TIMEOUT, 10);
    curl_setopt($http, CURLOPT_RETURNTRANSFER, 1);

    $result = curl_exec($http);

    if ($result === '')
        $errorMsg = "code不正确";

    if (curl_errno($http))
        $errorMsg = curl_error($http);
}

echo "$errorMsg";

echo $errorMsg;
echo $result;

curl_close($http);

if (empty($errorMsg))
    header("Location: index.php?token=$result");


这一步是不是有些晕,看得迷糊?没关系,其实这一步应该是倒数第二步
下面来实现token服务器的代码,它需要完成验证客户端传递过来的code(在实际情况下还会验证客户端的有效性),并返回可用的token

token.php

$redis = new Redis();
$redis->connect('127.0.0.1', '6379');

$token = '';
if (isset($_GET['code']) && $redis->get('code') === $_GET['code'])
{
    // 验证成功
    try
    {
        $token = md5(random_int(100, 3000));

        $redis->set('token', $token);
    } catch (Exception $e)
    {
    }
}

echo $token;

 

接下来,访问 你的域名/authorize.php?redirectUrl=callback.php,点击同意,查看显示结果,如何?理解了么?

没有理解也没有关系,我会详细解释,如果有什么不理解的,请对照上面的代码

这是阮一峰先生文章上步骤的截图,我们按照这个顺序一步一步来

(A)访问  你的域名/authorize.php?redirectUrl=callback.php

(B)点击同意

(C)同意后会跳转到 你的域名/callback.php?code=xxxx,接下来客户端回调向服务器申请令牌,通过curl,向token.php传递code参数,请求令牌

(D)这步来到了token.php中,主要就是验证code是否合法,然后发放令牌

(E)回调中这时已经获取了token,接下来是向资源服务器(这里是index.php)获取资源,带上刚刚获取的token

(F)回到index.php中,关注第7、8两行,这里验证token

这就是整个流程,当然实际中不止这么简单,但大体都是一样,像微信开发中的验证,也是如此。

如果仍然有什么不理解的,可以留下你的评论。

最后附上代码文件oauth.zip