การใช้ AuthSub กับไลบรารีของไคลเอ็นต์ .NET

Jeff Fisher ทีม Google Data APIs
สิงหาคม 2007

บทนำ: เหตุใด AuthSub จึงสำคัญ

ข้อดีของ Google Data APIs ("GData" แบบย่อ) คือการช่วยให้นักพัฒนาซอฟต์แวร์ สร้างแอปพลิเคชันที่โต้ตอบกับบริการของ Google ได้ กล่าวโดยละเอียดคือโทเค็นเหล่านี้ช่วยให้คุณเข้าถึงข้อมูลส่วนตัวของผู้ใช้เพื่อใช้ในแอปพลิเคชันได้ API ช่วยให้คุณ เขียนแอปพลิเคชันเพื่อซิงค์ นำเข้า ส่งออก และจัดการข้อมูลดังกล่าวได้ แม้ว่า API จะให้ความสามารถอันทรงพลังเหล่านี้แก่คุณ แต่คุณต้องอย่าลืมใช้ อย่างมีความรับผิดชอบ เนื่องจากข้อมูลผู้ใช้เป็นข้อมูลส่วนตัว คุณจึงต้องการเข้าถึงข้อมูลดังกล่าวอย่างปลอดภัย ส่วนสำคัญของกระบวนการนี้คือการตรวจสอบสิทธิ์ ไปยังเซิร์ฟเวอร์ของ Google อย่างปลอดภัย

สมมติว่าคุณมีเว็บแอปพลิเคชันใหม่ที่ยอดเยี่ยมซึ่งคุณต้องการเชื่อมโยงกับข้อมูลที่จัดเก็บไว้ในเว็บเซอร์วิสของ Google ตอนนี้คุณต้องตรวจสอบสิทธิ์เพื่อเข้าถึงข้อมูลส่วนตัวนี้ ทำไมไม่ใช้สิ่งที่ง่ายๆ อย่าง ClientLogin วิธีนี้ใช้ได้ แต่คุณจะต้องจัดการข้อมูลส่วนตัวมากขึ้น นั่นคือข้อมูลเข้าสู่ระบบของผู้ใช้ ClientLogin กำหนดให้แอปพลิเคชันของคุณต้องขอชื่อผู้ใช้และรหัสผ่าน Google ของผู้ใช้ ซึ่งเหมาะสำหรับแอปพลิเคชันเดสก์ท็อปที่ทำงานบนเครื่องส่วนตัวของผู้ใช้ แต่ไม่เหมาะสำหรับแอปพลิเคชันบนเว็บ นอกเหนือจากความรับผิดในการจัดการข้อมูลเข้าสู่ระบบเหล่านี้ในเซิร์ฟเวอร์ของคุณเองแล้ว ผู้ใช้บางรายที่ระมัดระวังมากกว่าอาจกังวลว่าคุณจะจัดเก็บข้อมูลของตน ข้อกังวลที่พบบ่อยอีกอย่างจากผู้ใช้คือหากต้องการให้สิทธิ์โปรแกรมเข้าถึงเฉพาะบริการใดบริการหนึ่ง (เช่น กิจกรรมใน Google ปฏิทิน) แต่ไม่ต้องการให้สิทธิ์เข้าถึงบริการอื่นๆ (เช่น เอกสารใน Google) AuthSub แก้ปัญหาทั้ง 2 อย่างนี้ได้โดยให้ผู้ใช้ตรวจสอบสิทธิ์ผ่านเซิร์ฟเวอร์ของ Google และอนุญาตให้โปรแกรมของคุณขอสิทธิ์เข้าถึงที่จำเป็นเท่านั้น

ตอนนี้คุณได้อ่านทฤษฎีเบื้องหลัง AuthSub มากพอแล้ว ก็ถึงเวลาไปเขียนโค้ดกัน สำหรับบทความนี้ ผมเลือกที่จะทำให้ทุกอย่างง่ายขึ้นและทำทุกอย่างภายในหน้า ASP เดียว แต่คุณควรจะสามารถผสานรวมเทคนิคที่แสดงที่นี่เข้ากับแอปพลิเคชันของคุณเองได้อย่างง่ายดาย

การจัดการการตรวจสอบสิทธิ์

แล้วคุณต้องทำอะไรบ้างจึงจะใช้ AuthSub ในเว็บแอปพลิเคชันได้จริงๆ ก่อนอื่น การนำเข้ามาตรฐานจากไลบรารีไคลเอ็นต์ GData มีดังนี้

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

ตอนนี้สิ่งแรกที่คุณต้องทำคือส่งผู้ใช้ไปยัง URL ที่สร้างขึ้นมาเป็นพิเศษ ซึ่งจะช่วยให้เซิร์ฟเวอร์ของ Google จัดการการตรวจสอบสิทธิ์และเปลี่ยนเส้นทางผู้ใช้กลับไปยังเว็บไซต์ของคุณได้ โชคดีที่คุณไม่จำเป็นต้องสร้าง URL นี้ด้วยตนเอง เนื่องจากมีวิธีการสร้าง URL ให้คุณ ยกตัวอย่างเช่น:

authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
  • target สตริงนี้มี URL ของเว็บแอปพลิเคชัน นี่คือตำแหน่งที่ระบบจะเปลี่ยนเส้นทางผู้ใช้ไปหลังจากตรวจสอบสิทธิ์
  • ขอบเขต สตริงนี้จะกำหนดโดย API ที่คุณใช้ ซึ่งสอดคล้องกับฟีดรายการใดรายการหนึ่งใน GData API เช่น ฟีดที่มีข้อมูลปฏิทินทั้งหมดสำหรับผู้ใช้คือ "http://www.google.com/calendar/feeds/default/private/full"
  • secure คือบูลีนที่แจ้งให้เซิร์ฟเวอร์ทราบว่าคุณลงทะเบียนกับ Google แล้วและจะลงนามในคำขอของคุณไปยังเซิร์ฟเวอร์ด้วยการเข้ารหัส โดยปกติแล้วอาร์กิวเมนต์นี้จะเป็นเท็จโดยค่าเริ่มต้น โดยเฉพาะอย่างยิ่งเมื่อทำงานในสภาพแวดล้อมการทดสอบ
  • session นี่คือบูลีนอีกรายการที่ระบุว่าคุณต้องการ "โทเค็นเซสชัน" แทน "โทเค็นที่ใช้ครั้งเดียว" บทบาทของอาร์กิวเมนต์นี้จะชัดเจนยิ่งขึ้นในอีกสักครู่

หลังจากที่ผู้ใช้คลิก URL ที่สร้างขึ้น ระบบจะนำผู้ใช้ไปยังหน้าบัญชี Google ซึ่งอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้บัญชี Google ของตนเองได้ จากนั้นระบบจะเปลี่ยนเส้นทางผู้ใช้กลับไปยังหน้าเว็บที่คุณระบุในตัวแปร "target" แต่มีพารามิเตอร์การค้นหา "token" ซึ่งมีโทเค็นที่ใช้ได้ครั้งเดียว โดยปกติแล้ว โทเค็นนี้จะใช้ได้เพียงครั้งเดียวเท่านั้น กล่าวคือ ใช้เพื่อดำเนินการอย่างใดอย่างหนึ่งกับฟีดที่ระบุได้ อย่างไรก็ตาม หากคุณระบุพารามิเตอร์ "session" เป็น true คุณจะแลกเปลี่ยนพารามิเตอร์ดังกล่าวเป็น "โทเค็นเซสชัน" ที่ใช้ซ้ำได้จนกว่าผู้ใช้จะสิ้นสุดเซสชัน โดยทำได้ดังนี้

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

ในส่วนนี้ คุณจะดึงโทเค็นจากพารามิเตอร์การค้นหาและแลกเปลี่ยนเป็น "โทเค็นเซสชัน" จากนั้นคุณสามารถเลือกจัดเก็บโทเค็นในอาร์เรย์ Session ของ .NET โดยอัตโนมัติเพื่อบันทึกไว้ใช้ในภายหลัง หรือจะเลือกจัดเก็บโทเค็นไว้ในฐานข้อมูลก็ได้ ขั้นตอนถัดไปคือการใช้โทเค็นนี้เพื่อส่งคำขอที่ผ่านการตรวจสอบสิทธิ์

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

ในส่วนนี้ คุณตั้งค่าออบเจ็กต์ CalendarService เพื่อโต้ตอบกับ Google Calendar API โดยใช้ AuthSub ในการตรวจสอบสิทธิ์ โปรดทราบว่า "cl" ที่ใช้ในตัวสร้างสำหรับ GAuthSubRequestFactory คือชื่อบริการของปฏิทิน คุณดูชื่อบริการอื่นๆ ได้ในคำถามที่พบบ่อยเกี่ยวกับ Google Data APIs

AuthSub ที่ปลอดภัย (ลงทะเบียนแล้ว)

หากเลือกลงทะเบียนเว็บแอปพลิเคชัน คุณจะเปิดใช้ความปลอดภัยอีกระดับขณะใช้ AuthSub ได้ ซึ่งจะช่วยให้คุณลงนามแบบดิจิทัลในคำขอทั้งหมดที่โค้ดของคุณสร้างขึ้นได้ เพื่อไม่ให้ผู้อื่นใช้โทเค็น AuthSub ที่ออกให้คุณได้ เว้นแต่จะมีคีย์ส่วนตัวของคุณ ขั้นตอนแรกคือการตรวจสอบว่าคุณสร้างลิงก์ AuthSub ที่ถูกต้องเมื่อเรียกใช้ AuthSubUtil.getRequestUrl โดยตั้งค่าอาร์กิวเมนต์ "secure" เป็น true คุณจะต้องทำการเปลี่ยนแปลงโค้ดอื่นๆ อีก 2 รายการ ดังนี้

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

...

authFactory.PrivateKey = rsaKey;

ก่อนอื่น โปรดสังเกตว่าตอนนี้คุณส่งตัวแปร "rsaKey" ไปยังเมธอด exchangeForSessionToken แทน null นอกจากนี้ ยังใช้ตัวแปรเดียวกันนี้เพื่อตั้งค่าพร็อพเพอร์ตี้ของ GAuthSubRequestFactory เมื่อตั้งค่าการเชื่อมต่อกับบริการด้วย ตัวแปร "rsaKey" คือ RSACryptoServiceProvider ที่สอดคล้องกับคอมโพเนนต์คีย์ส่วนตัวของใบรับรอง x509 ที่คุณลงทะเบียนกับ Google

การสร้างคีย์ส่วนตัว RSA และใบรับรองแบบ Self-signed อาจทำให้สับสนเล็กน้อย โดยเฉพาะอย่างยิ่งเนื่องจาก .NET Framework ไม่เข้าใจคีย์หรือใบรับรองที่จัดเก็บในรูปแบบ PEM คำสั่งต่อไปนี้แสดงวิธีสร้างคีย์ส่วนตัวและใบรับรองสาธารณะโดยใช้ชุดเครื่องมือ 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"

ขั้นตอนแรกจะสร้างคีย์ส่วนตัวและใบรับรอง X509 สาธารณะทั้ง 2 รายการในรูปแบบ PEM ชื่อ "test_key.pem" และ "test_cert.pem" ตามลำดับ โปรดทราบว่าระบบตั้งค่าให้ลงทะเบียนใบรับรองกับ "www.example.com" ซึ่งอยู่ใน Mountain View, CA, US แทนที่ค่าที่เหมาะสมสำหรับบริษัทของคุณที่นี่ ไฟล์ "test_cert.pem" มีข้อมูลที่คุณต้องส่งในหน้าการลงทะเบียน AuthSub

ขั้นตอนที่ 2 จะสร้างไฟล์ PFX จากคีย์ส่วนตัวและใบรับรอง คุณสามารถนำเข้าไฟล์นี้ไปยังไลบรารีของไคลเอ็นต์ .NET เพื่อลงนามในคำขอที่ส่งไปยัง GData API แบบดิจิทัล โค้ดต่อไปนี้แสดงวิธีนําเข้าคีย์ส่วนตัวจากไฟล์ PFX ไปยังเว็บแอปพลิเคชัน

protected AsymmetricAlgorithm getRsaKey()
{

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

  return privateKey;
}

ฟังก์ชัน getRsaKey() ที่กำหนดโดยข้อมูลโค้ดนี้สามารถใช้แทนตัวแปร "rsaKey" ที่แสดงด้านบนเมื่อใช้เพื่อตรวจสอบสิทธิ์กับ API แน่นอนว่าควรแทนที่เส้นทางของไฟล์ด้วยตำแหน่งที่เหมาะสมของไฟล์ PFX ที่คุณสร้างขึ้น

รายการโค้ดที่สมบูรณ์

วิธีที่ง่ายที่สุดในการแสดงวิธีใช้วิธีการที่แสดงในส่วนก่อนหน้าคือการใช้ตัวอย่างจริง โค้ดตัวอย่างต่อไปนี้เป็นหน้า ASP อย่างง่ายที่ใช้ AuthSub เพื่อตรวจสอบสิทธิ์ผู้ใช้ จากนั้นจะพิมพ์กิจกรรมใน Google ปฏิทินของผู้ใช้

<%@ 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>

บทสรุป

AuthSub ช่วยให้เว็บแอปพลิเคชันเข้าถึงข้อมูลที่จัดเก็บไว้ ในบัญชี Google ของผู้ใช้ได้อย่างปลอดภัยและมีการควบคุม การใช้ไลบรารีของไคลเอ็นต์ .NET จะช่วยให้คุณผสานรวมเว็บไซต์ที่ใช้ ASP กับบริการของ Google ได้อย่างง่ายดาย บทความนี้มีไว้เพื่อช่วยให้คุณเริ่มต้นใช้งานได้ แต่เราขอแนะนำให้คุณดูแหล่งข้อมูลเพิ่มเติมต่อไปนี้