文章目录

不积跬步无以至千里

记录精彩的程序人生

基于PHP实现纯正Auth2.0(原创) 有更新!

  aluaa

最近公司想基于OAuth2.0实现某个业务,为方便后续研究和分享,我打算写一篇完整的OAuth 2.0的技术文章,详细讲解它的原理和最终实现。

1、神马是OAuth 2.0 ?

   OAuth2.0(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不
需要将用户名和密码提供给第三方网。它主要解决如下问题:
   1、避免同一个用户在不同公司的APP之间频繁注册、登录,大大降低拉新用户门槛
   2、使第三方APP能共享到巨型APP(如微信、支付宝等)的用户信息(用户头像、昵称等)

注意:
1.OAuth 2.0本身不负责第三方APP/web等客户端的登录态、退出态
2.如果是公司多个内部系统(如OA/CRM/ERP等)想实现用户账号打通,共享登录态、退出态,单点登录SSO更适合你。所以要先搞清楚,你想要的是什么。

2、OAuth 2.0 最常用的使用场景

一般来讲,考虑使用OAuth 2.0的主要是我方公司和合作方公司进行合作,我方公司在行业积累了足够大的用户基数、用户信息、用户业务信息,合作方在
系统开发时需要我方(服务方)授权给合作方(第三方)基础的用户信息(用户的昵称、头像、性别等),方便第三方能把精力集中在自己业务上。
比如微信、支付宝、微博等很多大型公司都有自己授权第三方登录的开放平台。

3、OAuth 2.0 标准流程(authorization_code方式)

![WechatIMG222png](Qiniu settings failed, please visit https://hacpai.com/article/1442418791213 for more details)

4、开始OAuth 2.0 项目搭建:下载OAuth 2.0的PHP核心包

根目录:/srv/www/auth2/
git clone git@github.com:bshaffer/oauth2-server-php.git

5、新建站点

站点url:

url:www.auth2.local:8088

nginx配置:

server {
    listen 8088;
    server_name www.auth2.local;
    root /srv/www/auth2/;
    charset utf-8;
    location / {
        index index.html index.htm index.php;
    }
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

6、创建OAuth数据库和表

新建OAuth数据库auth2,并执行如下建表sql

CREATE TABLE oauth_clients (
  client_id             VARCHAR(80)   NOT NULL,
  client_secret         VARCHAR(80),
  redirect_uri          VARCHAR(2000),
  grant_types           VARCHAR(80),
  scope                 VARCHAR(4000),
  user_id               VARCHAR(80),
  PRIMARY KEY (client_id)
);

CREATE TABLE oauth_access_tokens (
  access_token         VARCHAR(40)    NOT NULL,
  client_id            VARCHAR(80)    NOT NULL,
  user_id              VARCHAR(80),
  expires              TIMESTAMP      NOT NULL,
  scope                VARCHAR(4000),
  PRIMARY KEY (access_token)
);

CREATE TABLE oauth_authorization_codes (
  authorization_code  VARCHAR(40)     NOT NULL,
  client_id           VARCHAR(80)     NOT NULL,
  user_id             VARCHAR(80),
  redirect_uri        VARCHAR(2000),
  expires             TIMESTAMP       NOT NULL,
  scope               VARCHAR(4000),
  id_token            VARCHAR(1000),
  PRIMARY KEY (authorization_code)
);

CREATE TABLE oauth_refresh_tokens (
  refresh_token       VARCHAR(40)     NOT NULL,
  client_id           VARCHAR(80)     NOT NULL,
  user_id             VARCHAR(80),
  expires             TIMESTAMP       NOT NULL,
  scope               VARCHAR(4000),
  PRIMARY KEY (refresh_token)
);

CREATE TABLE oauth_users (
  username            VARCHAR(80),
  password            VARCHAR(80),
  first_name          VARCHAR(80),
  last_name           VARCHAR(80),
  email               VARCHAR(80),
  email_verified      BOOLEAN,
  scope               VARCHAR(4000)
);

CREATE TABLE oauth_scopes (
  scope               VARCHAR(80)     NOT NULL,
  is_default          BOOLEAN,
  PRIMARY KEY (scope)
);

CREATE TABLE oauth_jwt (
  client_id           VARCHAR(80)     NOT NULL,
  subject             VARCHAR(80),
  public_key          VARCHAR(2000)   NOT NULL
);

插入一条测试app信息
INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES (“testclient”, “testpass”, “http://fake/”);

7、新建authorize.php授权文件

(该文件是用户确认的交互UI画面,用户点击同意会先获得authorization_code,然后再获取access_token)
在浏览器中打开如下连接,然后点击yes按钮
http://www.auth2.local:8088/authorize.php?response_type=code&client_id=testclient&state=xyz
获取的 authorization_code:243cd370e035881d0cc5bfb421ed7d5919f99d1f

require_once __DIR__ . '/server.php';

$request = OAuth2\Request::createFromGlobals();
$response = new OAuth2\Response();

// validate the authorize request
if (!$server->validateAuthorizeRequest($request, $response)) {
  $response->send();
  die;
}
// display an authorization form
if (empty($_POST)) {
  exit('  
  
  Do You Authorize TestClient?  
    
');
}

// print the authorization code if the user has authorized your client
$is_authorized = ($_POST['authorized'] === 'yes');
$user_id = 1;
$server->handleAuthorizeRequest($request, $response, $is_authorized, $user_id);
if ($is_authorized) {
  // this is only here so that you get to see your code in the cURL request. Otherwise, we'd redirect back to the client
  $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40);
  //exit("SUCCESS AND DO redirect_uri! Authorization Code: $code");
}
$response->send();

8、新建OAuth 2.0服务加载及token生成文件index.php并配置好数据库连接信息

require_once('oauth2-server-php/src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();

$dsn = 'mysql:dbname=auth2;host=192.168.200.7';
$username = 'root';
$password = 'admin';

$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
$server = new OAuth2\Server($storage);
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage)); //or any grant type you like!
$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();

9、获取access_token

curl -u testclient:testpass http://www.auth2.local:8088/index.php -d 'grant_type=authorization_code&code=243cd370e035881d0cc5bfb421ed7d5919f99d1f'

返回结果:

{
    "access_token": "fe2617e4034cb25044f6f22a7b2356ca6161c8a5",
    "expires_in": 3600,
    "token_type": "Bearer",
    "scope": null,
    "refresh_token": "8f9621f8fa9b6a857dffea7a67f4edc0fbdd8f8c"
}
validate