Sử dụng AuthSub với Thư viện ứng dụng .NET

Jeff Fisher, nhóm Google Data API
Tháng 8 năm 2007

Giới thiệu: Tại sao AuthSub lại quan trọng?

Điều tuyệt vời về API Dữ liệu của Google (gọi tắt là "GData") là cách họ cho phép các nhà phát triển xây dựng ứng dụng tương tác với các dịch vụ của Google. Cụ thể hơn, các API này cho phép bạn truy cập vào dữ liệu riêng tư của người dùng để sử dụng trong ứng dụng. Các API này cho phép bạn ghi các ứng dụng để đồng bộ hoá, nhập, xuất và quản lý dữ liệu đó. Mặc dù các API cấp cho bạn những khả năng mạnh mẽ này, nhưng bạn phải nhớ sử dụng chúng một cách có trách nhiệm. Vì dữ liệu người dùng là thông tin riêng tư, nên đương nhiên bạn muốn truy cập dữ liệu theo cách an toàn. Một phần quan trọng trong quá trình này là xác thực được với máy chủ của Google theo cách bảo mật.

Giả sử bạn có một ứng dụng web mới tuyệt vời mà bạn muốn liên kết với dữ liệu được lưu trữ trong các dịch vụ web của Google. Bây giờ, bạn muốn xác thực để truy cập vào dữ liệu riêng tư này. Tại sao không chỉ sử dụng một số thứ đơn giản, như ClientLogin? Điều đó sẽ thực hiện được mẹo, nhưng sau đó bạn sẽ xử lý nhiều dữ liệu cá nhân hơn: thông tin đăng nhập của người dùng. ClientLogin yêu cầu ứng dụng của bạn yêu cầu tên người dùng và mật khẩu Google của người dùng. Điều này chấp nhận được đối với ứng dụng dành cho máy tính chạy trên máy cá nhân của người dùng, nhưng không phù hợp với ứng dụng dựa trên web. Bên cạnh trách nhiệm xử lý các thông tin xác thực này trên máy chủ của riêng bạn, có lẽ một số người dùng thận trọng hơn sẽ lo ngại rằng bạn có thể lưu trữ thông tin của họ. Một mối quan tâm phổ biến khác của người dùng là họ chỉ muốn cấp quyền truy cập vào một dịch vụ cụ thể (như các sự kiện trên Lịch Google) nhưng không muốn cấp cho một số dịch vụ khác (như Tài liệu Google). AuthSub giải quyết cả hai vấn đề này bằng cách cho phép người dùng xác thực thông qua các máy chủ của Google và cho phép chương trình của bạn chỉ yêu cầu quyền truy cập mà chương trình cần.

Bạn đã đọc đủ về lý thuyết đằng sau AuthSub, đã đến lúc chuyển sang một số lập trình! Đối với bài viết này, tôi chọn cách đơn giản và thực hiện mọi thao tác bên trong một trang ASP, nhưng bạn có thể dễ dàng tích hợp các kỹ thuật được trình bày tại đây vào ứng dụng.

Xử lý việc xác thực

Vậy cần gì để sử dụng AuthSub trong ứng dụng web? Trước tiên, có một số dữ liệu nhập tiêu chuẩn từ thư viện ứng dụng GData:

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="System.Net" %>

Bây giờ, điều đầu tiên bạn cần làm là đưa người dùng đến một URL được tạo thủ công đặc biệt. Điều này cho phép máy chủ của Google xử lý việc xác thực và sau đó chuyển hướng người dùng quay lại trang web của bạn. May mắn là bạn không phải tạo URL này theo cách thủ công vì có một số phương pháp để thực hiện việc đó cho bạn. Hãy xem ví dụ:

authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
  • target Đây là một chuỗi chứa URL tới ứng dụng web của bạn. Đây là nơi người dùng sẽ được chuyển hướng đến sau khi xác thực.
  • scope Chuỗi này được xác định theo API mà bạn đang sử dụng. Dữ liệu này tương ứng với một trong các nguồn cấp dữ liệu trong API GData. Ví dụ: nguồn cấp dữ liệu chứa tất cả thông tin trên lịch cho người dùng là "http://www.google.com/calendar/feeds/default/private/full".
  • bảo mật Đây là một boolean cho máy chủ biết bạn đã đăng ký với Google và sẽ ký mã các yêu cầu của bạn đến máy chủ. Đối số này thường bị sai theo mặc định, đặc biệt khi làm việc trong môi trường thử nghiệm.
  • phiên Đây là một boolean khác cho biết rằng bạn muốn "mã thông báo phiên" thay vì "mã thông báo sử dụng một lần". Vai trò của đối số này sẽ trở nên rõ ràng hơn trong giây lát.

Sau khi người dùng nhấp vào URL được tạo, họ sẽ được đưa đến một trang Tài khoản Google cho phép họ đăng nhập vào Tài khoản Google của mình. Sau đó, chúng sẽ được chuyển hướng trở lại trang web mà bạn đã chỉ định trong biến "target", nhưng với tham số truy vấn "token" chứa mã thông báo sử dụng một lần. Thông thường, bạn có thể sử dụng mã thông báo này đúng một lần. Điều này có nghĩa là nó có thể được dùng để thực hiện một hành động trên một nguồn cấp dữ liệu nhất định. Tuy nhiên, nếu bạn chỉ định thông số "session" là true, thì thông số này có thể được đổi lấy "mã phiên" có thể được sử dụng lại cho đến khi người dùng kết thúc phiên. Bạn có thể thực hiện việc này theo cách sau:

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();

Tại đây, bạn trích xuất mã thông báo từ tham số truy vấn và đổi mã đó thành "mã phiên". Sau đó, để có thể lưu mã sau này sử dụng sau này, bạn có thể chọn lưu trữ mã này trong mảng Session tự động của .NET. Đương nhiên, bạn cũng có thể chọn lưu trữ mã thông báo trong cơ sở dữ liệu. Bước tiếp theo là sử dụng mã thông báo này để tạo một yêu cầu đã xác thực:

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "My-Cool-Application");
authFactory.Token = (String) Session["token"];
CalendarService service = new CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;

Tại đây, bạn thiết lập đối tượng CalendarService để tương tác với API Lịch Google bằng AuthSub để xác thực. Lưu ý "cl" được dùng trong hàm khởi tạo cho GAuthSubRequestFactory là tên dịch vụ cho Lịch. Bạn có thể tham khảo Câu hỏi thường gặp về API Dữ liệu của Google để biết các tên dịch vụ khác.

AuthSub bảo mật (đã đăng ký)

Nếu chọn đăng ký ứng dụng web, bạn có thể bật một cấp độ bảo mật bổ sung khi sử dụng AuthSub. Điều này cho phép bạn ký điện tử tất cả các yêu cầu do mã đưa ra, khiến người khác không thể sử dụng mã thông báo AuthSub được cấp cho bạn trừ khi họ có khoá riêng tư của bạn. Bước đầu tiên là đảm bảo bạn đang tạo đúng đường liên kết AuthSub khi gọi AuthSubUtil.getRequestUrl bằng cách đặt đối số "an toàn" thành true. Bạn sẽ cần thực hiện hai thay đổi khác về mã:

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, rsaKey).ToString();

...

authFactory.PrivateKey = rsaKey;

Trước tiên, hãy lưu ý thay vì null, giờ đây bạn sẽ chuyển biến "rsaKey" vào phương thức exchangeForSessionToken. Biến này cũng dùng để thiết lập thuộc tính của GAuthSubRequestFactory khi thiết lập kết nối với dịch vụ. Biến "rsaKey" là một RSACryptoServiceProvider tương ứng với thành phần khoá riêng tư của chứng chỉ x509 mà bạn đã đăng ký với Google.

Việc tạo khóa riêng tư RSA và chứng chỉ tự ký có thể hơi khó hiểu, đặc biệt là vì khung .NET không hiểu được các khóa hoặc chứng chỉ được lưu trữ ở định dạng PEM. Các lệnh sau đây cho biết cách tạo khoá riêng tư và chứng chỉ công khai bằng cách sử dụng bộ công cụ OpenSSL:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  test_key.pem -out test_cert.pem

openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem \
  -out test_cert.pfx -name "Testing Certificate"

Bước đầu tiên sẽ tạo một khoá riêng tư và một chứng chỉ X509 công khai ở định dạng PEM có tên "test_key.pem" và "test_cert.pem". Xin lưu ý rằng chứng chỉ này được đặt thành đăng ký tại "www.example.com" tại Mountain View, California, Hoa Kỳ. Thay thế các giá trị thích hợp cho công ty của bạn tại đây. Tệp "test_cert.pem" chứa thông tin bạn cần gửi trên trang đăng ký AuthSub.

Bước thứ hai tạo tệp PFX từ khoá riêng tư và chứng chỉ của bạn. Tệp này có thể được nhập vào thư viện ứng dụng .NET để ký các yêu cầu kỹ thuật số được gửi tới API GData. Đoạn mã sau đây cho biết cách bạn có thể nhập khoá riêng tư từ tệp PFX vào một ứng dụng web:

protected AsymmetricAlgorithm getRsaKey()
{

  X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx","");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;

  return privateKey;
}

Bạn có thể dùng hàm getRsaKey() do đoạn mã này xác định thay cho biến "rsaKey" hiển thị ở trên khi dùng để xác thực với các API. Thông thường, đường dẫn tệp phải được thay thế bằng vị trí thích hợp của tệp PFX mà bạn tạo.

Trang thông tin mã hoàn chỉnh

Ví dụ trực tiếp là cách dễ nhất để minh hoạ cách sử dụng các phương thức đã nêu trong phần trước. Mã mẫu sau đây là một trang ASP đơn giản sử dụng AuthSub để xác thực người dùng, sau đó in các sự kiện trên Lịch Google của họ.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="Google.GData.Calendar" %>
<%@ Import Namespace="System.Net" %>

<script runat="server">
    void PrintCalendar() {

        GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "TesterApp");
        authFactory.Token = (String) Session["token"];
        CalendarService service = new CalendarService(authFactory.ApplicationName);
        service.RequestFactory = authFactory;

        EventQuery query = new EventQuery();

        query.Uri = new Uri("http://www.google.com/calendar/feeds/default/private/full");

        try
        {
            EventFeed calFeed = service.Query(query);
            foreach (Google.GData.Calendar.EventEntry entry in calFeed.Entries)
            {
                Response.Write("Event: " + entry.Title.Text + "<br/>");
            }
        }
        catch (GDataRequestException gdre)
        {
            HttpWebResponse response = (HttpWebResponse)gdre.Response;
            
            //bad auth token, clear session and refresh the page
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                Session.Clear();
                Response.Redirect(Request.Url.AbsolutePath, true);
            }
            else
            {
                Response.Write("Error processing request: " + gdre.ToString());
            }
        }
    }

</script>


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Test Site</title>
</head>
<body>

    <form id="form1" runat="server">
    <h1>AuthSub Sample Page</h1>
    <div>
    <%
        GotoAuthSubLink.Visible = false;
        
        if (Session["token"] != null)
        {
            PrintCalendar();
        }
        else if (Request.QueryString["token"] != null)
        {
            String token = Request.QueryString["token"];
            Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
            Response.Redirect(Request.Url.AbsolutePath, true);
        }
        else //no auth data, print link
        {
            GotoAuthSubLink.Text = "Login to your Google Account";
            GotoAuthSubLink.Visible = true;
            GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(),
                "http://www.google.com/calendar/feeds/",false,true);
        }
        
     %>
    <asp:HyperLink ID="GotoAuthSubLink" runat="server"/>

    </div>
    </form>
</body>
</html>

Kết luận

AuthSub cho phép ứng dụng web của bạn truy cập vào dữ liệu được lưu trữ trong Tài khoản Google của người dùng theo cách an toàn và được kiểm soát. Việc sử dụng thư viện ứng dụng .NET giúp bạn dễ dàng tích hợp trang web dựa trên ASP của bạn với các dịch vụ của Google. Bài viết này nhằm giúp bạn bắt đầu, nhưng bạn có thể tham khảo các tài nguyên khác: