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

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

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

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

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

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

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

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

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

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

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

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

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 API เพื่อดูชื่อบริการอื่นๆ ได้

การตรวจสอบสิทธิ์ (ลงทะเบียน) ที่ปลอดภัย

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

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

...

authFactory.PrivateKey = rsaKey;

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

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