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

Bạn đang xem tài liệu về Apigee Edge.
Chuyển đến tài liệu về Apigee X.
thông tin

Chủ đề này thảo luận 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 để giới hạn lượng quyền truy cập được cấp cho mã truy cập. Ví dụ: mã truy cập cấp cho một ứng dụng khách có thể được cấp quyền READ và WRITE đối với các tài nguyên được bảo vệ hoặc chỉ quyền truy cập READ. Bạn có thể triển khai các API để thực thi bất kỳ phạm vi hoặc tổ hợp phạm vi nào 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à ứng dụng đó cố gắng gọi một điểm cuối API yêu cầu quyền ghi, thì lệnh gọi sẽ không thành công.

Trong chủ đề này, chúng ta sẽ thảo luận cách chỉ định phạm vi 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 có thể tự tin sử dụng phạm vi.

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

Khi tạo một mã truy cập, Edge có thể chỉ định một phạm vi cho mã thông báo đó. Để hiểu cách tình trạng này xảy ra, trước tiên, bạn cần biết các thực thể Apigee Edge sau đây: sản phẩm API, nhà phát triển và ứng dụng dành cho nhà phát triển. Để xem phần giới thiệu, hãy xem phần Giới thiệu về việc 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ự trông ngẫu nhiên cho phép Edge xác minh các yêu cầu API gửi đến (hãy coi đây là mã dự phòng cho thông tin xác thực 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à 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 về thời hạn, thông tin nhận dạng ứng dụng của nhà phát triển, nhà phát triển và các sản phẩm liên kết với mã thông báo đó. Bạn cũng sẽ nhận thấy siêu dữ liệu cũng bao gồm "phạm vi".

Mã thông báo lấy phạm vi của nó bằng cách nào?

Chìa khoá đầu tiên để tìm hiểu phạm vi là hãy nhớ rằng mỗi sản phẩm trong một ứng dụng của nhà phát triển có thể không được chỉ định phạm vi hoặc có nhiều phạm vi. Bạn có thể chỉ định các phạm vi này khi sản phẩm được tạo hoặc thêm sau này. Những dữ liệu này tồn tại dưới dạng một danh sách tên và xuất hiện trong "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 sản phẩm vào ứng dụng đó, Edge sẽ xem xét tất 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 danh sách toàn cầu của ứng dụng – một tập hợp tất cả các phạm vi được công nhận).

Khi một ứng dụng khách yêu cầu mã truy cập từ Apigee Edge, ứng dụng khách có thể tuỳ ý chỉ định 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 hỏi về phạm vi "A". Tức là ứng dụng yêu cầu máy chủ uỷ quyền (Edge) tạo một mã truy cập có phạm vi "A" (cấp quyền cho ứng dụng để gọi các API có phạm vi "A"). Ứng dụng 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 biết ứng dụng nào đang gửi yêu cầu và biết ứng dụng nào của nhà phát triển mà ứng dụng đã đă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ó bao gồm nên Edge cần quyết định xem có sản phẩm API nào 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 có 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 ra các phạm vi "A, B, X" và tham số truy vấn chỉ định "scope=X Y Z", thì chỉ có phạm vi "X" được chỉ định cho mã thông báo.

Nếu ứng dụng không đính kèm thông số phạm vi thì sao? 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 của nhà phát triển ghi nhận. Bạn cần hiểu rằng hành vi mặc định là trả về một mã truy cập chứa sự kết hợp của mọi phạm vi cho mọi sản phẩm có trong ứng dụng của nhà phát triển.

Nếu không có sản phẩm nào liên kết với ứng dụng của nhà phát triển chỉ định phạm vi, còn mã thông báo thì có phạm vi, thì các lệnh gọi 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 phạm vi chính của ứng dụng. Có thể là một sản phẩm trong ứng dụng có phạm vi A và B, còn một sản phẩm thứ hai có phạm vi C và D hoặc bất kỳ kiểu 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 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, mã thông báo sẽ nhận được một tập hợp phạm vi là sự hợp nhất của tất cả các phạm vi mà ứng dụng của nhà phát triển công nhận.

Có một trường hợp khác nữa là hành vi mặc định là trả về một mã truy cập có 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ụ: đây là chính sách GenerateAccessToken trong đó <Scope> được chỉ định. Nếu phần tử <Scope> đó bị thiếu (hoặc nếu phần tử này có mặt 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 ở đầu luồng proxy). Bạn phải chỉ định thao tác VerifyAccessToken cho chính sách này. Hãy cùng 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>

Hãy lưu ý phần tử <Scope>. Giá trị này được 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 chỉ được áp dụng nếu mã truy cập có phạm vi "A". Nếu phần tử <Scope> này bị bỏ qua 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, với 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 thực hiện việc này bằng cách thiết kế các luồng tuỳ chỉnh có đính kèm các chính sách VerifyAccessToken có nhận biết phạm vi.

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 có /resourceA trong hậu tố của đườ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 là hợp lệ và xem mã này hỗ trợ những phạm vi nào. Nếu bạn thiết lập chính sách 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 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ế biện pháp thực thi theo phạm vi cho API của mình. Chúng thực hiện việc này bằng cách tạo 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 tìm hiểu một số lệnh gọi API mẫu để minh hoạ cách mã thông báo nhận phạm vi và cách thực thi phạm vi.

Cách viết hoa 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à phạm vi của những sản phẩm đó hợp nhất là: A, B và C. Lệnh gọi API này yêu cầu một 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 đã tạo sẽ được cung cấp trong 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"
}

Bây giờ, giả sử bạn có một điểm cuối API có phạm vi "A" (nghĩa là điểm cuối đó 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>

Dưới đây là lệnh gọi mẫu đến và đ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 thành công:

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

Quy trình 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, còn mã thông báo truy cập đã được cấp các phạm vi A, B và C (một hành vi mặc định).

Trường hợp lọc

Giả sử bạn có một ứng dụng của nhà phát triển với các sản phẩm có phạm vi A, B, C và X. Bạn yêu cầu một mã truy cập và đưa vào 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 đã tạo sẽ được cấp trong 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 của nhà phát triển nhận dạng phạm vi A, B, C và X. Trong trường hợp này, bạn sẽ 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ì 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 proxy API xác thực. 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"
 }
 

Quá trình này thành công vì chính sách VerifyAccessToken yêu cầu phạm vi A hoặc X, đồng thời mã thông báo 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

Điều quan trọng là bạn phải nắm được cách Apigee Edge xử lý các phạm vi OAuth 2.0. Dưới đây là những điểm chính cần ghi nhớ:

  • Ứng dụng của nhà phát triển "công nhận" sự kết hợp của tất 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 phạm vi mà ứng dụng muốn có. Việc tìm ra phạm vi mà quá trình này sẽ thực sự chỉ định cho mã truy cập dựa trên (a) phạm vi được yêu cầu và (b) phạm vi mà ứng dụng của nhà phát triển công nhận là tuỳ thuộc vào quá trình xác định phạm vi mà quá trình này sẽ chỉ định cho mã truy cập.
  • Nếu bạn không định cấu hình Apigee Edge để kiểm tra phạm vi (phần tử <Scope> trong chính sách VerifyAccessToken bị trống hoặc bị 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 được ứng dụng nhà phát triển đã đăng ký nhận dạng (một trong các phạm vi thuộc danh sách phạm vi "chính" của ứng dụng).
  • Nếu một mã truy cập không liên kết với phạm vi nào, thì mã sẽ chỉ thành công trong trường hợp Edge không xem xét phạm vi (phần tử <Scope> bị thiếu trong chính sách VerifyAccessToken hoặc bị trống).