Làm việc với các phạm vi OAuth2

Bạn đang xem tài liệu về Apigee Edge.
Truy cập vào tài liệu Apigee X.
thông tin

Chủ đề này thảo luận về cách sử dụng phạm vi OAuth 2.0 trên Apigee Edge.

Phạm vi OAuth2 là gì?

Phạm vi OAuth 2.0 cung cấp một cách để hạn chế mức độ truy cập được cấp cho mã truy cập. Ví dụ: mã truy cập được cấp cho một ứng dụng khách có thể được cấp quyền ĐỌC và GHI đối với các tài nguyên được bảo vệ hoặc chỉ có quyền ĐỌC. Bạn có thể triển khai các API để thực thi mọi phạm vi hoặc tổ hợp phạm vi mà bạn muốn. Vì vậy, nếu một ứng dụng nhận được mã thông báo có phạm vi READ và cố gắng gọi một điểm cuối API yêu cầu quyền WRITE, thì lệnh gọi sẽ không thành công.

Trong chủ đề này, chúng ta sẽ thảo luận về cách phạm vi được chỉ định cho mã truy cập và cách Apigee Edge thực thi phạm vi OAuth 2.0. Sau khi đọc chủ đề này, bạn sẽ có thể tự tin sử dụng các phạm vi.

Phạm vi được chỉ định cho mã truy cập như thế nào?

Khi tạo mã truy cập, Edge có thể chỉ định một phạm vi cho mã đó. Để hiểu cách điều này xảy ra, trước tiên, bạn phải làm quen với các thực thể Apigee Edge sau: sản phẩm API, nhà phát triển và ứng dụng của nhà phát triển. Để biết thông tin giới thiệu, hãy xem phần Giới thiệu về tính năng xuất bản. Bạn nên xem lại tài liệu này (nếu cần) trước khi tiếp tục.

Mã truy cập là một chuỗi dài gồm các ký tự có vẻ ngẫu nhiên, cho phép Edge xác minh các yêu cầu API đến (hãy coi mã này là một giải pháp thay thế cho thông tin đăng nhập tên người dùng/mật khẩu thông thường). Về mặt kỹ thuật, mã thông báo là một khoá đề cập đến một tập hợp siêu dữ liệu có dạng như sau:

{
  "issued_at" : "1416962591727",
  "application_name" : "0d3e1d41-a59f-4d74-957e-d4e3275d4781",
  "scope" : "A",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-bs0cSuqS9y]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-AdBmANhsag@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "eTtB7w5lvk3DnOZNGReBlvGvIAeAywun",
  "access_token" : "ODm47ris5AlEty8TDc1itwYPe5MW",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

Siêu dữ liệu của mã thông báo bao gồm chuỗi mã truy cập thực tế, thông tin hết hạn, thông tin nhận dạng ứng dụng nhà phát triển, nhà phát triển và các sản phẩm được liên kết với mã thông báo. Bạn cũng sẽ nhận thấy rằng siêu dữ liệu cũng bao gồm "phạm vi".

Mã thông báo có được phạm vi như thế nào?

Khoá đầu tiên để hiểu phạm vi là nhớ rằng mỗi sản phẩm trong một ứng dụng của nhà phát triển có thể có không hoặc nhiều phạm vi được chỉ định cho sản phẩm đó. Bạn có thể chỉ định các phạm vi này khi tạo sản phẩm hoặc thêm sau. Chúng tồn tại dưới dạng danh sách tên và được đưa vào "siêu dữ liệu" liên kết với từng sản phẩm.

Khi bạn tạo một ứng dụng dành cho nhà phát triển và thêm các sản phẩm vào ứng dụng đó, Edge sẽ xem xét tất cả các sản phẩm trong ứng dụng dành cho nhà phát triển và tạo một danh sách tất cả các phạm vi cho những sản phẩm đó (danh sách phạm vi chính hoặc phạm vi chung của ứng dụng – một tập hợp của tất cả các phạm vi được nhận dạng).

Khi yêu cầu mã truy cập từ Apigee Edge, ứng dụng khách có thể tuỳ ý chỉ định những phạm vi mà ứng dụng đó muốn liên kết với mã thông báo đó. Ví dụ: yêu cầu sau đây yêu cầu phạm vi "A". Tức là ứng dụng đang yêu cầu máy chủ uỷ quyền (Edge) tạo mã truy cập có phạm vi "A" (cho phép ứng dụng gọi các API có phạm vi "A"). Ứng dụng sẽ gửi một yêu cầu POST như sau:

curl -i -X POST -H Authorization: Basic Mg12YTk2UkEIyIBCrtro1QpIG -H content-type:application/x-www-form-urlencoded http://myorg-test.apigee.net/oauth/token?grant_type=client_credentials&scope=A

Điều gì sẽ xảy ra?

Khi nhận được yêu cầu này, Edge sẽ biết ứng dụng nào đang đưa ra yêu cầu và biết ứng dụng nhà phát triển nào mà ứng dụng khách đã đăng ký (mã ứng dụng khách và khoá bí mật của ứng dụng được mã hoá trong tiêu đề xác thực cơ bản). Vì tham số truy vấn scope được đưa vào, nên Edge cần quyết định xem có sản phẩm API nào được liên kết với ứng dụng của nhà phát triển có phạm vi "A" hay không. Nếu có, mã truy cập sẽ được tạo với phạm vi "A". Một cách khác để xem xét vấn đề này là tham số truy vấn phạm vi là một loại bộ lọc. Nếu ứng dụng của nhà phát triển nhận dạng các phạm vi "A, B, X" và tham số truy vấn chỉ định "scope=X Y Z", thì chỉ phạm vi "X" được chỉ định cho mã thông báo.

Điều gì sẽ xảy ra nếu ứng dụng không đính kèm tham số phạm vi? Trong trường hợp này, Edge sẽ tạo một mã thông báo bao gồm tất cả các phạm vi mà ứng dụng nhà phát triển nhận dạng được. Điều quan trọng là bạn phải hiểu rằng hành vi mặc định là trả về một mã truy cập chứa hợp của tất cả các phạm vi cho tất cả các sản phẩm có trong ứng dụng nhà phát triển.

Nếu không có sản phẩm nào liên kết với một ứng dụng của nhà phát triển chỉ định phạm vi và mã thông báo có phạm vi, thì các lệnh gọi được thực hiện bằng mã thông báo đó sẽ không thành công.

Giả sử một ứng dụng của nhà phát triển nhận ra các phạm vi sau: A B C D. Đây là danh sách chính về các phạm vi của ứng dụng. Có thể một sản phẩm trong ứng dụng có phạm vi A và B, còn sản phẩm thứ hai có phạm vi C và D, hoặc bất kỳ tổ hợp nào. Nếu ứng dụng không chỉ định tham số scope (hoặc nếu ứng dụng chỉ định tham số phạm vi mà không có giá trị), thì mã thông báo sẽ được cấp cả 4 phạm vi: A, B, C và D. Xin nhắc lại rằng mã thông báo sẽ nhận được một tập hợp các phạm vi là hợp của tất cả các phạm vi mà ứng dụng nhà phát triển nhận dạng được.

Có thêm một trường hợp nữa mà hành vi mặc định là trả về mã truy cập với tất cả các phạm vi được nhận dạng, đó là khi chính sách GenerateAccessToken (chính sách Apigee Edge tạo mã truy cập) không chỉ định phần tử <Scope>. Ví dụ: sau đây là chính sách GenerateAccessToken, trong đó <Scope> được chỉ định . Nếu thiếu phần tử <Scope> đó (hoặc nếu phần tử đó có nhưng trống), thì hành vi mặc định sẽ được thực thi.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-GenerateAccessToken">
    <DisplayName>OAuthV2 - Generate Access Token</DisplayName>
    <Attributes>
      <Attribute name='hello' ref='system.time' display='false'>value1</Attribute>
    </Attributes>
    <Scope>request.queryparam.scope</Scope> 
    <GrantType>request.formparam.grant_type</GrantType>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>GenerateAccessToken</Operation>
    <SupportedGrantTypes>
      <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
  <GenerateResponse enabled="true"/>
</OAuthV2>

Phạm vi được thực thi như thế nào?

Trước tiên, hãy nhớ rằng trên Apigee Edge, mã truy cập được xác thực bằng chính sách OAuthV2 (thường được đặt ngay từ đầu một luồng proxy). Chính sách phải chỉ định thao tác VerifyAccessToken. Hãy xem chính sách này:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope> <!-- Optional: space-separated list of scope names. -->
    <GenerateResponse enabled="true"/>
</OAuthV2>

Lưu ý phần tử <Scope>. Tham số này dùng để chỉ định những phạm vi mà chính sách sẽ chấp nhận.

Trong ví dụ này, chính sách sẽ chỉ thành công nếu mã truy cập bao gồm phạm vi "A". Nếu bạn bỏ qua phần tử <Scope> này hoặc nếu phần tử này không có giá trị, thì chính sách sẽ bỏ qua phạm vi của mã truy cập.

Giờ đây, nhờ khả năng xác thực mã truy cập dựa trên phạm vi, bạn có thể thiết kế các API để thực thi các phạm vi cụ thể. Bạn có thể thực hiện việc này bằng cách thiết kế các quy trình tuỳ chỉnh có chính sách VerifyAccessToken nhận biết phạm vi được đính kèm.

Giả sử API của bạn có một luồng được xác định cho điểm cuối /resourceA:

<Flow name="resourceA">
            <Condition>(proxy.pathsuffix MatchesPath "/resourceA") and (request.verb = "GET")</Condition>
            <Description>Get a resource A</Description>
            <Request>
                <Step>
                    <Name>OAuthV2-VerifyAccessTokenA</Name>
                </Step>
            </Request>
            <Response>
                <Step>
                    <Name>AssignMessage-CreateResponse</Name>
                </Step>
            </Response>
        </Flow>

Khi quy trình này được kích hoạt (một yêu cầu đến có /resourceA trong hậu tố đường dẫn), chính sách OAuthV2-VerifyAccessTokenA sẽ được gọi ngay lập tức. Chính sách này xác minh rằng mã truy cập hợp lệ và xem mã truy cập hỗ trợ(các) phạm vi nào. Nếu chính sách được định cấu hình như ví dụ bên dưới, với <Scope>A</Scope>, thì chính sách sẽ chỉ thành công nếu mã truy cập có phạm vi "A". Nếu không, hàm này sẽ trả về lỗi.

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Tóm lại, nhà phát triển API chịu trách nhiệm thiết kế việc thực thi phạm vi vào API của họ. Họ thực hiện việc này bằng cách tạo các luồng tuỳ chỉnh để xử lý các phạm vi cụ thể và đính kèm các chính sách VerifyAccessToken để thực thi các phạm vi đó.

Ví dụ về mã

Cuối cùng, hãy xem xét một số ví dụ về lệnh gọi API để minh hoạ cách mã thông báo nhận được phạm vi và cách phạm vi được thực thi.

Trường hợp mặc định

Giả sử bạn có một ứng dụng dành cho nhà phát triển có các sản phẩm và hợp nhất các phạm vi của những sản phẩm đó là: A, B và C. Lệnh gọi API này yêu cầu mã truy cập nhưng không chỉ định tham số truy vấn phạm vi.

curl -X POST -H content-type:application/x-www-form-urlencoded http://wwitman-test.apigee.net/scopecheck1/token?grant_type=client_credentials

Trong trường hợp này, mã thông báo được tạo sẽ có các phạm vi A, B và C (hành vi mặc định). Siêu dữ liệu của mã thông báo sẽ có dạng như sau:

{
  "issued_at" : "1417016208588",
  "application_name" : "eb1a0333-5775-4116-9eb2-c36075ddc360",
  "scope" : "A B C",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-yEgQbQqjRR]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-yxiuHuZcDW@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "atGFvl3jgA0pJd05rXKHeNAC69naDmpW",
  "access_token" : "MveXpj4UYXol38thNoJYIa8fBGlI",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

Giả sử bạn có một điểm cuối API có phạm vi "A" (tức là VerifyAccessToken yêu cầu phạm vi "A"). Sau đây là chính sách VerifyAccessToken:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Sau đây là một lệnh gọi mẫu đến điểm cuối thực thi phạm vi A:

curl -X GET -H Authorization: Bearer MveXpj4UYXol38thNoJYIa8fBGlI http://wwitman-test.apigee.net/scopecheck1/resourceA 

Lệnh gọi GET này sẽ thành công:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }

Thao tác này thành công vì chính sách VerifyAccessToken được kích hoạt khi điểm cuối được gọi yêu cầu phạm vi A và mã truy cập được cấp các phạm vi A, B và C – hành vi mặc định.

Trường hợp lọc

Giả sử bạn có một ứng dụng dành cho nhà phát triển có các sản phẩm có phạm vi A, B, C và X. Bạn yêu cầu mã truy cập và thêm tham số truy vấn scope, như sau:

curl -i -X POST -H content-type:application/x-www-form-urlencoded 'http://myorg-test.apigee.net/oauth/token?grant_type=client_credentials&scope=A X'

Trong trường hợp này, mã thông báo được tạo sẽ có phạm vi A và X, vì cả A và X đều là phạm vi hợp lệ. Hãy nhớ rằng ứng dụng dành cho nhà phát triển nhận dạng các phạm vi A, B, C và X. Trong trường hợp này, bạn đang lọc danh sách sản phẩm API dựa trên các phạm vi này. Nếu một sản phẩm có phạm vi A hoặc X, bạn có thể định cấu hình các điểm cuối API sẽ thực thi các phạm vi này. Nếu một sản phẩm không có phạm vi A hoặc X (giả sử sản phẩm đó có phạm vi B, C và Z), thì bạn không thể gọi các API thực thi phạm vi A hoặc X bằng mã thông báo.

Khi bạn gọi API bằng mã thông báo mới:

curl -X GET -H Authorization: Bearer Rkmqo2UkEIyIBCrtro1QpIG http://wwitman-test.apigee.net/scopecheck1/resourceX

Mã truy cập được xác thực bằng proxy API. Ví dụ:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenX">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A X</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Lệnh gọi GET kích hoạt thành công và trả về một phản hồi. Ví dụ:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }
 

Thao tác này thành công vì chính sách VerifyAccessToken yêu cầu phạm vi A hoặc X, còn mã truy cập bao gồm phạm vi A và X. Tất nhiên, nếu phần tử <Scope> được đặt thành "B", thì lệnh gọi này sẽ không thành công.

Tóm tắt

Bạn cần hiểu cách Apigee Edge xử lý các phạm vi OAuth 2.0. Sau đây là những điểm chính cần ghi nhớ:

  • Ứng dụng của nhà phát triển "nhận ra" sự kết hợp của tất cả các phạm vi được xác định cho tất cả sản phẩm của ứng dụng đó.
  • Khi yêu cầu mã truy cập, ứng dụng có thể chỉ định những phạm vi mà ứng dụng muốn có. Apigee Edge (máy chủ uỷ quyền) sẽ xác định những phạm vi mà máy chủ này thực sự chỉ định cho mã truy cập dựa trên (a) (các) phạm vi được yêu cầu và (b) những phạm vi được ứng dụng nhà phát triển nhận dạng.
  • Nếu Apigee Edge không được định cấu hình để kiểm tra phạm vi (phần tử <Scope> bị thiếu trong chính sách VerifyAccessToken hoặc phần tử này trống), thì lệnh gọi API sẽ thành công miễn là phạm vi được nhúng trong mã truy cập khớp với một trong các phạm vi mà ứng dụng nhà phát triển đã đăng ký nhận dạng (một trong các phạm vi trong danh sách phạm vi "chính" của ứng dụng).
  • Nếu mã truy cập không có phạm vi nào liên kết với mã đó, thì mã truy cập sẽ chỉ thành công trong trường hợp Edge không xem xét phạm vi (thiếu phần tử <Scope> trong chính sách VerifyAccessToken hoặc phần tử này bị bỏ trống).