最近公司想基于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"
}
友情提示:垃圾评论一律封号...