Home  >  Article  >  php教程  >  Use OAuth2-Server-php to build OAuth2 Server on the Yii framework

Use OAuth2-Server-php to build OAuth2 Server on the Yii framework

WBOY
WBOYOriginal
2016-08-18 08:57:521018browse

Original text reproduced from http://www.cnblogs.com/ldms/p/4565547.html

Yii has many extensions available. After checking the OAuth-related extensions provided on the Yii official website, I found several OAuth2 client extensions, but I did not find an extension that can be used as an OAuth2 Server. Because Yii is a well-organized and easily extensible framework, it can be integrated with other PHP OAuth2 Server implementations. On the OAuth.net/2/ official website, several OAuth2 Servers implemented in PHP are provided. The first OAuth2-Server-php is used here as the OAuth2 Server extension of the Yii framework. Some necessary integration operations are required, mainly writing a class to accept client access and issue access_token, etc.

Part One: Database Preparation

The database structure used by OAuth2-Server-php adopts the table structure (Schema) provided by oauth2-server-php README.md on Github. There are five tables in total:

mysql> show tables ;
+--------------------------+
| Tables_in_oauth2 |
+------------- ------------+
| oauth_access_token |
| oauth_authorization_code |
| oauth_client |
| oauth_refresh_token |
| user |
+--------------- -----------+
5 rows in set (0.00 sec)

The name of each table describes the content accessed in the table. The table name can be customized. The customization location is: OAuth2/Storage In the config array at line 48 of /Pdo.php, because the mysql database is used here, Pdo needs to be modified. If other storage solutions are used, such as Redis, just modify the corresponding files yourself. Note that the database names here are all in singular form.

Use the following sql statements to create these 5 tables and add a test client:
##############################
  ### oauth2 tables
  #############################
  drop table if exists `oauth_client`;
  drop table if exists `oauth_access_token`;
drop table if exists `oauth_authorization_code`;
drop table if exists `oauth_refresh_token`;
drop table if exists `user`;

CREATE TABLE `oauth_client` (
`client_id` VARCHAR(80) NOT NULL,
`client_secret` VARCHAR(80) NOT NULL,
`redirect_uri` VARCHAR(2000) NOT NULL,
​ CONSTRAINT client_id_pk PRIMARY KEY (client_id)
  );

  CREATE TABLE `oauth_access_token` (
`access_token` VARCHAR(40 ) NOT NULL,
`client_id` VARCHAR(80) NOT NULL,
`user_id` VARCHAR(255),
`expires` TIMESTAMP NOT NULL,
`scope` VARCHAR(2000),
  CONSTRAINT access_token_pk PRIMARY KEY (access _token)
; 000),
`expires` TIMESTAMP NOT NULL,
`scope` VARCHAR(2000),
CONSTRAINT auth_code_pk PRIMARY KEY (authorization_code)
);

CREATE TABLE `oauth_refresh_token` (
`refresh_to ken` VARCHAR(40) NOT NULL,
`client_id ` VARCHAR(80) NOT NULL,
`user_id` VARCHAR(255),
`expires` TIMESTAMP NOT NULL,
`scope` VARCHAR(2000),
​ CONSTRAINT refresh_token_pk PRIMARY KEY (refresh_token)
​ );

-
CREATE TABLE `user` (
`user_id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(255) NOT NULL,
`password` VARCHAR(2000),
`first_name` VARCHAR(255),
`last_ name ` VARCHAR(255),
  CONSTRAINT user_pk PRIMARY KEY (user_id)
);
-- test data
INSERT INTO oauth_client (client_id, client_secret, redirect_uri)
VALUES ("testclient", "testpass", "http://fake/");
INSERT INTO user (username, password, first_name, last_name)
VALUES ('rereadyou', '8551be07bab21f3933e8177538d411e43b78dbcc', 'bo', 'zhang');


Part 2: Authentication scheme and implementation

The OAuth2 RFC 6749 specification provides four basic authentication schemes. The following is for these four authentications. The solutions and how they are used in this implementation are discussed separately.

The first authentication method: Authorization Code Grant

The authorization code is obtained by using the authorization server as an intermediary between the client and the resource owner. Rather than requesting authorization directly from the resource owner, the client directs the resource owner to an authorization server (by a user agent defined in RFC2616), which then directs the resource owner back to the client with an authorization code.

Before guiding the resource owner to return to the client with the authorization code, the authorization server will identify the resource owner and obtain his authorization. Because the resource owner authenticates only with the authorization server, the resource owner's credentials do not need to be shared with the client.

Authorization codes provide some important security benefits, such as the ability to verify the client's identity, and the transmission of the access token directly to the client rather than passing it through the resource owner's user agent and potentially exposing it to others (including resource owner).

The authorization code permission type is used to obtain access tokens and refresh tokens and is optimized for confidential clients. Since this is a redirect-based process, the client must be able to interact with the resource owner's user agent (usually a web browser) and be able to receive incoming requests from the authorization server (via redirects). Z Authorization Code Grant Process (also known as web server flow) See as follows:
+-----------+
| Resource |
| Owner |
+---------------------------------------------------------- --- -(A)-- & Redirection URI ---->| | User- | Authorization |
| Agent +----(B)-- User authenticates --->Server |
| |                                                                          +------------ ---+
                                                                                                |
|                                        +---------+                                                                                                                       | Client | & Redirection URI |
| | | ---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)

Note: The straight line describing steps (A), (B) and (C) is divided into two parts because it passes through the user agent.
​ Figure 1: Authorization Code Process

​ The process shown in Figure 1 consists of the following steps:

​ (A) The client begins the process by directing the resource owner's user agent to the authorization endpoint. The client includes its client identity, request scope, local state, and a redirect URI to which the authorization server will send the user agent back once access is granted (or denied).
 (B) The authorization server verifies the identity of the resource owner (via the user agent) and determines whether the resource owner grants or denies the client's access request.
(C) Assuming the resource owner grants access, the authorization server redirects the user agent back to the client using the redirect URI provided previously (at request time or when the client registered). The redirect URI includes the authorization code and any local status previously provided by the client.
 (D) The client requests an access token from the authorization server's token endpoint by including the authorization code received in the previous step. When making a request, the client authenticates with the authorization server. The client includes the redirect URI used to obtain the authorization code for authentication.
​ (E) The authorization server authenticates the client, verifies the authorization code, and ensures that the redirect URI received matches the URI used to redirect the client in step (C). If passed, the authorization server responds with an access token and optional refresh token.

Process implementation:
1. Client app uses app id to obtain authorization code:

www.yii.com/oauth2/index.php?r=oauth2/authroize&response_type=code&client_id=testclient&state=xyz

Return: $authcode = authorization code.
Tips: Authorization code will expired in 30s. You can modify the constructor configuration parameters of the AuthorizationCode class in OAuth2/ResponseType/AuthorizationCode.php to customize the authorization_code validity time.
Client_id is the application name previously registered on this Server, which belongs to the scope of client management.
This step requires the user (resource owner) to log in to the OAuth2 Server to complete the authorization operation. User login belongs to the category of user management and is not a function that should be written in OAuth2 Server.
After logging in, the user can choose the operations (authorization) that he can open to the client app.
In this step of the binding process, from a security perspective, the user should be forced to re-enter the username and password to confirm the binding. Do not directly read the current user session for binding.

2. Obtain access_token:
      The client app uses authorization code to exchange for access_token

curl -u testclient:testpass www.yii.com/oauth2/index.php?r=oauth2/token -d "grant_type=authorization_code&code=$authcode

                                                           17bedd6e07ccc3f402",
"expires_in":3600,
"token_type":"bearer",
"scope":null,
"refresh_token":"269a623f54171e8598b1852eefcf115f4882b820"
          }

                                                                                                                                                                                                                                                                                   Failed: :"Authorization code doesn't exist or is invalid for the client"
    }

    Tip: This step requires using the client's client_id and client_secret and the authorization_code obtained in the previous step to exchange for access_code. It can be modified in the constructor configuration in the AccessToken class in OAuth2/ResponseType/AccessToken.php



Second authentication method: Implicit (implicit authentication)
The implicit authorization type is used to obtain the access token. token (it does not support issuing refresh tokens) and is optimized for public clients that know the specific redirect URI of the operation. These clients are usually implemented in the browser using a scripting language such as JavaScript

Since this is a redirect-based client. Directed flow, the client must be able to interact with the resource owner's user agent (usually a web browser) and be able to receive incoming requests from the authorization server (via redirects)

Unlike the client requesting authorization and authorization respectively. Authorization code grant type for the access token that the client receives as a result of the authorization request.

 Implicit permission types do not include client authentication but rely on resource owner presence and registration of the redirect URI. Because the access token is encoded into the redirect URI, it may be exposed to the resource owner and other applications residing on the same device.

The authorization verification process using the Implicit Grant method to obtain Access Token is also called User-Agent Flow, which is suitable for all applications without server-side cooperation (since applications are often located in a User Agent, such as a browser, such applications Also known as Client-Side Application on some platforms), such as mobile/desktop client programs, browser plug-ins, etc., as well as applications based on script client script languages ​​such as JavaScript. One of their common characteristics is that the application cannot Keep your App Secret Key properly. If you adopt the Authorization Code mode, there is a possibility of leaking your App Secret Key. The process diagram is as follows:

                                                                               (B )
+----|-----+ Client Identifier +---------------+
| | +----(A)-- & Redirection URI -- ->| |User- |Authorization |
|Agent |----(B)-- User authenticates -->| Server |
| |                                               )--- Redirection URI ----<|     |          |          with Access Token     +---------------+
     |          |            in Fragment
     |          |                                +---------------+
     |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
     |          |          without Fragment      |     Client    |
     |          |                                |    Resource   |
     |     (F)  |<---(E)------- Script ---------<|               |
     |          |                                +---------------+
     +-|--------+
       |    |
      (A)  (G) Access Token
       |    |
       ^    v
     +---------+
     |         |
     |  Client |
     |         |
     +---------+

     注:说明步骤(A)和(B)的直线因为通过用户代理而被分为两部分。

     图2:隐式许可流程

    图2中的所示流程包含以下步骤:

    (A)客户端通过向授权端点引导资源所有者的用户代理开始流程。客户端包括它的客户端标识、请求范围、本地状态和重定向URI,一旦访问被许可(或拒绝)授权服务器将传送用户代理回到该URI。
    (B)授权服务器验证资源拥有者的身份(通过用户代理),并确定资源所有者是否授予或拒绝客户端的访问请求。
    (C)假设资源所有者许可访问,授权服务器使用之前(在请求时或客户端注册时)提供的重定向URI重定向用户代理回到客户端。重定向URI在URI片段中包含访问令牌。
    (D)用户代理顺着重定向指示向Web托管的客户端资源发起请求(按RFC2616该请求不包含片段)。用户代理在本地保留片段信息。
    (E)Web托管的客户端资源返回一个网页(通常是带有嵌入式脚本的HTML文档),该网页能够访问包含用户代理保留的片段的完整重定向URI并提取包含在片段中的访问令牌(和其他参数)。
    (F)用户代理在本地执行Web托管的客户端资源提供的提取访问令牌的脚本。
    (G)用户代理传送访问令牌给客户端。

     Tips: 1. 一般不需提供 client_secret,仅需 client_id,单用户同样需要认证。
       2. Implicit Grant Type 不支持 refresh_token(或可自行实现)机制。
       3. THE FIRST TIME THE USER AUTHENTICATES YOUR APP USING IMPLICIT GRANT FLOW STORE THE ACCESS TOKEN! Once you have the access token do not try to re-authenticate. Your access token that you stored should continue to work!
          一旦获取 access_token (存在于 redirect_uri 的 fragment 中, 即 uri 中的 # 部分),Client 需要自己存储 access_token。
       4. 比较适用于 Client-Side Application,如手机/桌面客户端程序、浏览器插件等

oauth2-server-php implements this authorization method as follows:

1. This authorization method is included in the Authorization Code Grant (a simplification of the Authorization Code Grant method).

When initializing OAuth2Controller, just add AuthorizationCode type authorization to OAuth2 Server, as follows:
          $server->addGrantType(new OAuth2GrantTypeAuthorizationCode($storage));

  Authorization Code does not support Implicit by default, Grant needs to Server Change 'allow_implicit' on line 104 of .php to 'true' to enable implicit authorization.


2. Get access_token

http://www.yii.com/oauth2/index.php?r=oauth2/authorize&response_type=token&client_id=testclient&state=xyz&redirect_uri=www.baidu.com

Parameters: response_type=token ( Required, fixed value)
                                                                                                                                                                off Because implicit authorization does not require obtaining the authorization code.
Return:
Success:
The user needs to click the authorization button first.
                SUCCESS! Authorization Code: www.baidu.com?#access_token=9f0c38b475e51ccd3

                                                                                                                                   .
             {"error":"redirect_uri_mismatch","error_description":"The redirect URI provided is missing or does not match","error_uri":"http://tools.ietf.org/html/rfc6749#section-3.1. 2"}

access_token exists in the fragment in the redirect_uri, that is, after the '#' symbol, the client needs to extract the access_token in the fragment and save it. Developers should note that some user agents do not support the inclusion of fragment components in the HTTP "Location" HTTP response header field. These clients need to use a method other than a 3xx redirect response to redirect the client - for example, return an HTML page that contains a "continue" button with an action linked to the redirect URI.


The third authentication method: Resource Owner Password Credentials (Resource Owner Password Credentials Permission)

​ The Resource Owner Password Credentials permission type is suitable for situations where the resource owner has a trust relationship with the client, such as the device operating system or advanced Privileged applications. The authorization server should take special care when enabling this license type and only when no other process is available.

This permission type is suitable for clients that can obtain the resource owner's credentials (username and password, usually interactively). It is also used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest Authentication to OAuth by converting stored credentials into access tokens.

                                 +----------+
                                          Password Credentials
                                                                                                                          ------>| |
| | Password Credentials | Authorization |
| Client | ional Refresh Token) | --------+                                  +---------------+

     图3:资源所有者密码凭据流程

     图3中的所示流程包含以下步骤:

(A) The resource owner provides the client with its username and password.
​ (B) The client requests an access token from the authorization server's token endpoint by including the credentials received from the resource owner. When making a request, the client authenticates with the authorization server.

(C) The authorization server authenticates the client, verifies the resource owner's credentials, and if valid, issues an access token.


Tips: The client must discard the credentials once it obtains the access token.

oauth2-server-php implements Resource Owner Password Credentials as follows:

1. First add support for the Resource Owner Password Credentials authorization method in the constructor of Oauth2Controller and add the following code:

$server->addGrantType (new OAuth2GrantTypeUserCredentials($storage));

2. Get access_token:

curl -u testclient:testpass www.yii.com/oauth2/index.php?r=oauth2/token -d 'grant_type=password&username=rereadyou&password= rereadyou'

Return:
{"access_token":"66decd1b10891db5f8f63efe7cc352ce326895c6",
"expires_in":3600,
"token_type":bear" er",
"scope":null,
"refresh_token":"b5fa0c24e786e37e7ce7d6e2f911805dc65a0d7c"}

Tips: There is no user_id field in the sql schema user table provided by oauth2-server-php on Github [12]. You need to add this field yourself (primary key, auto_increment).
The user table design uses sha1 digest method without adding salt.
                                                                                                                                                                                                                                     ==sha1($password );
            }
                                                                                                                                                                                                         With With regard to user authentication, this function needs to be rewritten.



The fourth authentication method: Client Credentials Grant (Client Credentials Grant)

When the client requests access to what it controls, or negotiates with the authorization server in advance (the method used is beyond the scope of this specification) For protected resources of other resource owners, the client can request an access token using only its client credentials (or other supported authentication methods).

The client credentials permission type must be used by confidential clients only.

                                                                                                                         
| | & Gt;-(A) -Client Authentication --- & GT; | Authorization |
| Client | | Server |
| & LT;-(B) ---- Access Token -------------------------- --<|                                                                                                                                                                                    +---------------+

                                                                                 
The flow shown in Figure 4 contains the following steps:

(A) The client authenticates with the authorization server and requests an access token from the token endpoint.

(B) The authorization server authenticates the client and, if valid, issues an access token.

Tips: This is the simplest authentication method.

Since client authentication is used as the authorization permission, no other authorization request is required.

The implementation is as follows:
1. Add support for client authentication method in Oauth2Controller:

$server->addGrantType(new OAuth2GrantTypeClientCredentials($storage));
credentials 2. Get access_token:

curl -u testclient ;
                                                                                                         "scope":null}

Tips: Client directly uses its own client id and client_secret to obtain access_token;
RFC6749 specification specifies [10] clinet crendentials does not include refresh_token when client authentication obtains access_token. However, OAUTH2-Server-PHP provides a control switch. At Oauth2/GrantTypes/Clientcredials.php No. 33 [11],
The default $ Includereshtoken = False; Oken also issued Refresh_token.


Part 3: access_token type description
The client needs to present access_token to the server when operating data resources (through API). How to present access_token and access_token types is explained in the following section.
There are two types of access_token described in IETF rfc 6749: Bearer type and MAC type.
Since OAuth2-Server-php is still under development for MAC type access_token, only the most commonly used Bearer type access_token is explained below.

There are three ways to send the bearer access_token resource to the resource server in the resource request [13]. The client cannot use more than one method to transmit the token per request.
a. When sending an access token in the "Authorization" request header field defined by HTTP/1.1 [RFC2617], the client uses the "Bearer" authentication scheme to transmit the access token.

GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM

Clients should initiate authentication requests with a bearer token using the "Authorization" request header field with the "Bearer" HTTP authorization scheme. The resource server must support this method.

b. Form-encoded body parameters
When sending an access token in the HTTP request entity body, the client uses the "access_token" parameter to add the access token to the request body. The client cannot use this method unless all of the following conditions are met:
The entity header of the HTTP request contains the "Content-Type" header field set to "application/x-www-form-urlencoded".
   The entity body follows the encoding requirements of the "application/x-www-form-urlencoded" content type defined by HTML4.01 [W3C.REC-html401-19991224].
The HTTP request entity body is a single part.
         Content encoded in the entity body must consist entirely of ASCII [USASCII] characters.
          HTTP request method is the syntax defined by the request body. In particular, this means that the "GET" method cannot be used.采 端 The client uses the transmission layer to safely initiate the following http request:

Post/Resource http/1.1
host: server.example.com
contact-type: Application/x-www-Form-UrlenCoded
Access_token = mf_9.b5f -4.1JqM

c. When sending an access token in the HTTP request URI, the client takes the "access_token" parameter and adds the access token to the query part of the request URI defined in "Uniform Resource Identifier (URI): Common Syntax" RFC3986 Card.

                                                                                                                                                         The client may use transport layer security to initiate the following HTTP request:

                                                                                                     . The access token cannot be transmitted in the "Authorization" request header field or in the HTTP request entity body.

The above three ways of using access_token proposed in the rfc6750 specification. It is recommended to use the first option. The use of Bearer token requires TLS to ensure the security of access_token transmission.


Part 4: Using Bearer access_token to call api

1. Use refresh_token in exchange for access_token:
curl -u testclient:testpass www.yii.com/oauth2/index.php?r=oauth2/token -d "grant_type =refresh_token&refresh_token=1ce1a52dff3b5ab836ae25714c714cb86bf31b6f"

Return:
{"access_token":"50540a7ead3a27cdb458b6cdc38df25f64da18f 1",
"expires_in":3600,
"token_type":"bearer",
"scope":null}
There is no new refresh_token here, it is needed To configure to re-obtain refresh_token, you can modify 'always_issue_new_refresh_token' => true in the RefreshToken class __construct method in OAuth2/GrantType/RefreshToken.php to enable issuance of new refresh_token.
Tips: Partial description of refresh_token section in IETF rfc2649,
POST /token HTTP/1.1
Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type =refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

You need to provide the client_id and client_secret, and the grant_type value must be refresh_token.
The refresh_token cannot be used to exchange for a new access_token during the validity period of the access_token.

2. Use access_token:
a. The client app uses access_token to obtain resource information.
oauth2-server verification access_token:
curl www.yii.com/oauth2/index.php?r=oauth2/verifytoken -d 'access_token=aea4a1059d3194a3dd5e4117bedd6e07ccc3f402'

Return:
           {"result":"success",
"message":"your access token is valid."
                                                 This part is just to verify the validity of the access token. The client app should not call this method directly, but the server will call it by itself when requesting resources, and proceed based on the judgment result. Different treatments.
You can modify the validity period of access_token in Server.php of Oauth2 extension.

3. scope
Scope requires the server to determine specific feasible operations.
Scope is used to determine the operation permissions that the client can perform. The operation permissions in the project are controlled by srbac and will not be processed in Oauth2 for the time being.

4. state
state is the random hash parameter passed to the OAuth2 Server and returned by the OAuth2 Server when the client app obtains the authorization code in the first step. The state parameter is mainly used to prevent cross-site request forgery (Cross Site Request Forgery, CSRF). For related discussions, please see references [7] and [8] at the end of this article.


References:

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn