2010-01-17

Introduction to Composite Pattern

-->
Design patterns, CAB & SCSF

Hai phần trước đã nói sơ qua về CAB. Nhưng thật sự thì chưa có gì đọng lại ngoài những cái tên. Tiếp theo chúng ta sẽ điểm qua các Design patterns sử dụng trong CAB và SCSF. Các design patterns không thể liệt kê hết trong phần này mà cần tham khảo trong suốt những phần tiếp theo. Nếu một pattern được sử dụng trong CAB và SCSF cần tham khảo để tiếp tục thì mình sẽ bổ sung. Có thể tham khảo các design patterns tại http://www.dofactory.com/Patterns/Patterns.aspx
Giới thiệu Composite Pattern
 Đầu tiên sẽ đề cập đến design pattern cơ bản là Composite. Có thể tham khảo bài viết tại http://sourcemaking.com/design_patterns/composite.

Composite UML class diagram (sử dụng abstract class)

Composite UML class diagram (sử dụng interface)

Trong UML class diagram có thể thấy 3 phần chính
- Leaf là các đối tượng thành phần (hay còn gọi là Primitive).

- Component là giao diện cho các đối tượng thành phần, khai báo các method căn bản, là giao diện dùng khi access các thành phần.

- Composite định nghĩa các thao tác trên đối tượng thành phần, thực hiện lưu trữ và quản lý các đối tương thành phần.

Composite Pattern cho phép nhóm các object thành một single instance của một object. Các objects được nhóm có tính năng khá tương tự nhau. Object kết quả gọi là composite object. Việc thêm một component vào composite được hình dung tương tự việc thêm vào tree. Về kỹ thuật tất cả các Design patterns đều xoay quanh những tính năng của OOP encapsulation, inheritance, polymorphism...

Trong Composite kỹ thuật chính là polymorphism với 2 cách implement là polymorphism thông qua interface (recommended) và polymorphism qua abstract class.

Lab dành cho Composite Pattern

Ví dụ đơn giản khi có các region:
(England: (London: Chelsea)) và (France: Paris) nhóm thành Europe, một region lớn hơn như sau:

(Europe: (England: (London: Chelsea)) (France: Paris))

-->
Source code với C# (thực hiện qua interface)
Component.cs
-->

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Component interface
    /// </summary>
    interface Component
    {

        /// <summary>
        ///     Get the string of component (demo for component operation)
        /// </summary>
        ///
        ///     String of component
        /// </returns>
        string operation();

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        List<Component> getChildren();

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        void add(Component c);

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        bool remove(Component c);
    }
}

Composite.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Composite
    /// </summary>
    class Composite : Component
    {

        /// <summary>
        ///     ID
        /// </summary>
        private string _id;

        /// <summary>
        ///     Children collection
        /// </summary>
        private List<Component> _components = new List<Component>();

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///    
        /// </param>
        public Composite(string id)
        {
            _id = id;
        }

        #region [ INTERFACE IMPLEMENTATION ]

        /// <summary>
        ///     Operation
        /// </summary>
        /// <returns>
        ///     A string value present name and list of children recursive
        /// </returns>
        public string operation()
        {
            string s = " (" + _id + ":";
            this.getChildren().ForEach
            (
                delegate(Component child)
                {
                    s += " " + child.operation();
                }
            );

            return s + ") ";
        }

        /// <summary>
        ///     Implement interface get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        public List<Component> getChildren()
        {
            return _components;
        }

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public void add(Component c)
        {
            _components.Add(c);
        }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public bool remove(Component c)
        {
            return _components.Remove(c);
        }

        #endregion

    }
}

Leaf.cs
-->

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Leaf
    /// </summary>
    class Leaf : Component
    {

        /// <summary>
        ///    
        /// </summary>
        private string _id;

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///     ID
        /// </param>
        public Leaf(string id)
        {
            _id = id;
        }

        #region [ INTERFACE IMPLEMENTATION ]

        /// <summary>
        ///    
        /// </summary>
        /// <returns>
        ///     A string value...
        /// </returns>
        public string operation()
        {
            return _id;
        }

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     Just return null
        /// </returns>
        public List<Component> getChildren()
        {
            return null;
        }

        /// <summary>
        ///     Add to children collection, do nothing
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public void add(Component c) { }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     Just return false
        /// </returns>
        public bool remove(Component c) { return false; }

        #endregion

    }
}



Program.cs
-->
using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Program
    /// </summary>
    class Program
    {

        /// <summary>
        ///     Main entry point
        /// </summary>
        /// <param name="args" type="string[]">
        ///    
        /// </param>
        static void Main(string[] args)
        {

            // England
            Composite england = new Composite("England");

            // London
            Composite london = new Composite("London");
            london.add(new Leaf("Chelsea"));
            england.add(london);

            // Manchester
            Leaf manchester = new Leaf("Manchester");
            england.add(manchester);
            england.remove(manchester);

            // France
            Composite france = new Composite("France");
            france.add(new Leaf("Paris"));

            // Europe
            Composite europe = new Composite("Europe");
            europe.add(england);
            europe.add(france);

            // Get Europe
            Console.WriteLine(europe.operation());
            Console.ReadKey();
        }
    }
}

Source code với C# (thực hiện qua abstract class)
Component.cs
-->

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Component interface
    /// </summary>
    public abstract class Component
    {

        /// <summary>
        ///     ID
        /// </summary>
        protected string _id;

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///    
        /// </param>
        public Component(string id)
        {
            _id = id;
        }

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        public abstract List<Component> getChildren();

        /// <summary>
        ///     Get the string of component (demo for component operation)
        /// </summary>
        /// <returns>
        ///     String of component
        /// </returns>
        public abstract string operation();

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public abstract void add(Component c);

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public abstract bool remove(Component c);
    }
}


Composite.cs
-->
using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Composite
    /// </summary>
    class Composite : Component
    {

        /// <summary>
        ///     Children collection
        /// </summary>
        private List<Component> _components = new List<Component>();

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///    
        /// </param>
        public Composite(string id)
            : base(id)
        { }

        #region [ OVERRIDE METHODS ]

        /// <summary>
        ///     Operation
        /// </summary>
        /// <returns>
        ///     A string value present name and list of children recursive
        /// </returns>
        public override string operation()
        {
            string s = " (" + _id + ":";
            this.getChildren().ForEach(delegate(Component child) { s += " " + child.operation(); });
            return s + ") ";
        }

        /// <summary>
        ///     Implement interface get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        public override List<Component> getChildren()
        {
            return _components;
        }

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public override void add(Component c)
        {
            _components.Add(c);
        }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public override bool remove(Component c)
        {
            return _components.Remove(c);
        }

        #endregion

    }
}

Leaf.cs
-->
using System;
using System.Collections.Generic;
using System.Text;


namespace DesignPatterns
{

    /// <summary>
    ///     Leaf
    /// </summary>
    class Leaf : Component
    {

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///     ID
        /// </param>
        public Leaf(string id) : base(id) { }

        #region [ OVERRIDE METHODS ]

        /// <summary>
        ///    
        /// </summary>
        /// <returns>
        ///     A string value...
        /// </returns>
        public override string operation()
        {
            return _id;
        }

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     Just return null
        /// </returns>
        public override List<Component> getChildren()
        {
            return null;
        }

        /// <summary>
        ///     Add to children collection, do nothing
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public override void add(Component c) { }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     Just return false
        /// </returns>
        public override bool remove(Component c) { return false; }

        #endregion

    }
}

Qua bài này chúng ta sẽ chính thức tìm hiểu CAB. Part tiếp theo sẽ là part đầu tiên và mình sẽ đánh số cho dễ theo dõi bắt đầu là Part 1.

Design patterns, CAB & SCSF

Design patterns, CAB & SCSF

Mục đích phần này
- Tìm hiểu khái quát các design patterns được sử dụng, hiểu cấu trúc căn bản của CAB.
- Tìm hiểu khái quát SCSF (Smart Client Software Factory).

Khái quát về CAB
Thiết kế của CAB dựa trên 3 điểm chính như sau:
- Thực hiện tìm và loading các modules tại thời điểm khởi tạo ứng dụng để thực hiện build tự động solution.
- Tách biệt việc develop UI và shell khỏi việc develop business logic.
- Đạt được khả năng tái sử dụng và module hóa code bằng cách cung cấp các kỹ thuật “liên kết yếu” (loosely coupled)

Subsytems của CAB
Tìm và load modules
Mục tiêu chính của CAB là hỗ trợ việc phát triển ứng dụng từ nhưng module độc lập nhưng lại có thể liên kết với nhau. Mục tiêu này có thể đạt được nhờ những điểm sau:
- Implement một catalog, catalog này mô tả và chỉ định modules nào sẽ được load.
- Một module loader thực hiện load và initialize các module có trong application.

Việc implement này có thể customize nhưng không cần chỉnh sửa core implementation của CAB (các subsystems của CAB đề hoạt động như các plug-ins). Ví dụ có thể load danh sách các modules từ web service vào ứng dụng thay vì đọc danh sách từ file.

User Interface và Shell
Thông thường để developer có kiến thức sâu business logic được yêu cầu và có cả kỹ thuật tốt trong việc phát triển UI và Shell là không đơn giản. Trong những dự án có khối lượng công việc lớn để đảm bảo tính nhất quán và khả năng phát triển nhanh chóng (productivity, consistency) cần phát triển các resuable components bao hàm cả bussiness logic. CAB cung cấp các kiến trúc và kỹ thuật quanh việc tạo các component dựa trên Windows Forms bao gồm:
- Một cách nhất quán để show và hide controls sử dụng Workspaces. Một shell developer tạo visual effects, layout strategies hay các behaviors khác nhưng không ảnh hưởng business logic component.
- Một cách chung để thêm và sử dụng một UIElement vào shell như menu items, status bars một cách dễ dàng mà không cần phải quá quan tâm làm cách nào để cách thành phần đó có thể hiển thị tại vị trí cần thiết...
- Một kiến trúc Command cho phép business logic developer có thể định nghĩa các action mà user có thể thực hiện và cách mà những action này sẽ hiển thị trên một shell cụ thể.

Khả năng thiết kế các business logic thành những module
Các tính năng cho phép thực hiện các module với “liên kết yếu”
- WorkItems cung cấp một cách thực hiện phạm vi hóa dễ dàng các components tham gia chung 1 trường hợp sử dụng (use case), chia xẻ chung trạng thái (share state), events và các common services.
- EventBroker cung cấp một cơ chế “liên kết yếu” bằng event many-to-many (many-to-many, loosely coupled event system mechanism between objects) giữa các objects trong ứng dụng.
- Chia xẻ trạng thái bằng State cho phép các component có thể lưu trữ và lấy thông tin.

Các tính năng chính khác
- Thực hiện loading tự động cách modules độc lập vào một common shell.
- Dùng Event Broker để tạo một giao tiếp “liên kết yếu” (loosely coupled communication) giữa các modules và giữa các parts của module.
- Sử dụng và implement sẵn Command Pattern
- Implement sẵn các base classes theo MVC (Model-View-Control) pattern.
- Tạo framework cho các pluggable infrastructure services như authentication services, authorization services, module location, và module loding service.

CAB-SCSF: Làm quen với Composite UI Application Block

Phần này dựa trên các document cũ mà mình đã viết chủ yếu focus .NET Framework 2.0 và Visual Studio 2005

-->
Dựa trên series của Rich

Mục đích chung
- Tự xác định lại khả năng và hiểu biết về develop software nói chung và develop với công nghệ Microsoft.
- Nâng cao khả năng develop trên nền Microsoft .NET Framework và các khái niệm của software development. Tiếp cận với các khái niệm cần thiết trong quá trình phát triển software chuyên nghiệp.
- Xác định yêu cầu self-training và tham khảo materials là cần thiết với developer.

CAB-SCSF - Composite UI Application Block & Smart Client Software Factory

Các resources về CAB-SCSF:

Smart Client – Composite UI Application Block

Smart Client Software Factory

New Guidance and Tools for Building Integrated Desktop Applications

CAB viết tắt của Composite UI Application Block là một application block được phát triển bởi Microsoft trên nền Microsoft .NET Framework 2.0. CAB cung cấp các reusable source code dưới dạng các component dùng để tạo các complex smart client UI. Các components này được thiết kế theo các well-known design patterns như Composite, Command... Với thiết kế các UI part theo design patterns có thể dễ dàng tích hợp nhiều phần đơn giản để tạo các complex solutions trong khi giai đoạn phát triển có thể là độc lập (develop, test hay deploy).
 
Đối tượng có thể tìm hiểu: software architecturessoftware developers đã nắm vững các kỹ thuật trên nền tảng Microsft .NET Framework 2.0, nắm các kiến thức cần có về ngôn ngữ lập trình. Trong quá trình tìm hiểu nếu tự thấy không thể nắm bắt được những khái niệm hay hướng dẫn trong tài liệu này, yêu cầu tự tìm tài liệu nghiên cứu phần trước đó và những khái niệm bổ trợ.
 
Yêu cầu software và language:
- Language C#
- IDE: Visual Studio .NET 2005 Team hoặc 2008 Team
- NUnit hoặc test module trong IDE

Yêu cầu cài đặt chung:

UNnit

Enterprise Library for .NET Framework 2.0

Composite UI Application Block in C#

Guidance Automation Extensions

Guidance Automation Toolkit

Introduction to CAB-SCSF


Mặc dù CAB và SCSF đã ra từ lâu nhưng làm việc với nó cũng là một trải nghiệm thú vị. Hiện nay Microsoft đang khuyến khích dùng Windows Presentation Foundation (WPF) cho tương lai của Smart Client và từ từ rời bỏ WinForms application. Qua thời gian làm việc như một trainer trong in-house project mình hiểu thế nào là khó khăn mà junior developer gặp phải khi mới biết sơ sơ .NET đã phải làm quen với một application framework. Thời gian và pratice là 2 điều quan trọng nhất nhưng lại bị o ép bởi deadline cho dù mục tiêu khi nào cũng đặt ra là product và thòng thêm training. Và một khi project gặp khó khăn thì những người không biết gì sẽ quy kết cho junior developer là thiếu kinh nghiệm và khả năng học tập :(. Tất nhiên vị trí trainer cũng bị ảnh hưởng :P. Rảnh rỗi nên post về SCSF và hy vọng có thời gian để tiếp tục post về các framework đang dùng.



Phần lớn những gì viết ở đây được lấy từ series rất nổi tiếng của Rich Newman tại http://richnewman.wordpress.com/intro-to-cab-toc/. Một vài phần lấy từ blog MSDN và SCSF hand-on laps. Cá nhân mà nói thì các articles của Rich Newman tốt hơn cả guidance của Microsoft.


Về roadmap cho developer có thể tham khảo qua article trên C# corner 
http://www.c-sharpcorner.com/UploadFile/tjayram/DeveloperRoadmapForBuildingSmartClientApplications08062006192216PM/DeveloperRoadmapForBuildingSmartClientApplications.aspx

Thời gian hoàn thành theo roadmap thường đề cập là khoảng 5 năm trong khi mình cũng chỉ ra trường mới 5 năm :(. Nếu cứ theo như vậy thì công nghệ sắp tới sẽ bỏ ở đâu và tại Việt Nam công ty hay tổ chức nào thực sự muốn làm theo những công nghệ này. Code for fun ...


2009-12-22

Web services API design suggestion ???

Trước khi chuẩn bị design một web services API langxang đã đọc và tham khảo rất nhiều resources trên net. Mục đích muốn focus vào RESTful hơn là SOAP nhưng vấn đề nan giải nhất là security. Mới thử một suggestion nhưng vẫn còn nhiều chuyện phải nghĩ ... nói chung chẳng có gì hoàn hảo cả, chắc phải nghĩ vậy thôi.

Mình đã từng đọc đâu đó trên InfoQ câu này
REST is simple. Applying Enterprise-class Security is not.

1. Giới thiệu

Web services và format support

Tạo một bộ RESTful web services hỗ trợ XML và JSON qua HTTP.

Cơ chế authenticate và authorization

Các yếu tố cần suy nghĩ đến là user experience UX[1], OpenID support (federate-authentication) cũng như resources trong thời điểm hiện tại.
Yêu cầu đặt ra là một cơ chế flexible, lightweight. Tất nhiên không thể tốt hoàn toàn nhưng cần đạt mức chấp nhận được (về security, thời gian thực hiện ...).
Suggestion là một mô hình dạng token signing lấy ý tưởng từ Flickr API (thay vì dùng OAuth). Trong thời gian tới sẽ cố gắng hoàn thiện hệ thống API, có thể thực hiện support OAuth trong thời gian tới.

Các thành phần cần thực hiện

  1. Thiết kế và định nghĩa các APIs.
  2. Server viết bằng PHP thực hiện các chức năng: đăng ký API key, xử lý authenticate, xử lý authorization và RESTful request.
  3. Library C# SDK wrap các API
  4. Library PHP SDK wrap các API (optional)
2. Cơ chế authenticate và authorization (tham khảo Flickr Authentication API[3])

Authentication prerequisites

Tất cả các ứng dụng muốn sự dụng Authenticate API phải đăng ký một API key (đáp ứng yêu cầu có thể monitor ứng dụng) và phải thiết lập các thông số sau để có thể có API key
  1. Application title
  2. Application description
  3. Application logo graphic (optional)
  4. Application ’about’ URL (for example application introduction and download, optional)

Authentication methods

Sau khi đăng ký API key, ứng dụng sẽ được cung cấp secret key dùng trong quá trình signing (signing request process). Ứng dụng sẽ chọn 1 trong 2 methods chứng thực – web based hoặc non-web based.
Hiện tại sẽ support dạng non-web based authentication. Tương lai sẽ mở rộng hỗ trợ 3 loại như sau: web based authentication, non-web base authentication và mobile authentication.

3. Authentication dành cho non-web based application

Hiện tại Flickr sử dụng message digest algorithms MD5[7] theo đó desktop và non-web based application sẽ thực hiện giao tiếp với server để nhận được token. Tuy nhiên với những hạn chế của message digest algorithms MD5 có thể phải thay đổi so với cách thực hiện của Flickr[4] [5] [6]. Chi tiết xem phần signing process.
Đầu tiên desktop application thực hiện gọi API method auth.getFrob, method này yêu cầu signing (xem phần thực hiện signing). Nếu thành công method sẽ response một ‘frob’, dùng để construct một URL cho phép user thực hiện đăng nhập (launch system’s default browser) http://www.company.com/services/auth/?api_key=[api_key]&perms=[perms]&frob=[frob]&api_sig=[api_sig]
API signature là kết quả của signing process.
Permission yêu cầu user thực hiện grant, đối với trường hợp hiện tại chúng ta có thể omit. Đối với user log in vào system sẽ thực hiện cấp quyền tương ứng với user đó (yêu cầu làm rõ chức năng và cách xử lý của server).
Như vậy URL thực hiện authenticate là:
http://www.company.com/services/auth/?api_key=[api_key]&frob=[frob]&api_sig=[api_sig]
Hệ thống sẽ yêu cầu user log in với username/password hay OpenID. Tên application và mô tả của application sẽ được hiển thị (trong trường hợp quyết định permission theo role sau khi đăng nhập không cần hiển thị permissions mà ứng dụng mong muốn có). Nếu user đăng nhập thành công thay vì redirect về callback URL như web application, system sẽ hiển thị thông báo user log in thành công và hướng dẫn quay về application (và có thể close trang thông báo này).
Sau khi user thực hiện chứng thực thành công, quay lại application để báo cho application biết đã xong quá trình chứng thực. Application cần thực hiện gọi API method auth.getToken bằng cách cung cấp api_key và frob (method này yêu cầu signing, xem phần thực hiện signing).
Response sẽ bao gồm authentication token cần thực hiện các API call sau này (các thông tin khác kèm theo ví dụ summary của user profile, yêu cầu làm rõ sau).

Renewing non-web based authentication tokens

Để kiểm tra cần renewing hay có đủ permission hay không, application cần thực hiện gọi auth.checkToken. Nếu token không hợp lệ hoặc không đủ permission, application cần yêu cầu một token mới giống như các bước yêu cầu token đầu tiên.

Implementation guidelines

User profile data (bao gồm auth tokens) nên được lưu lại tại local user's 'profile', theo đó có thể cho phép switch user với cơ chế multiple profiles/users mà không thực hiện sharing auth data. Trong môi trường Windows có thể thực hiện dựa vào registry trong phần HKEY_CURRENT_USER, hay trong user's home directory đối với OSX/Unix.
Users phải được cung cấp chức năng 'logout'.

4. Authentication permissions

Application không nên yêu cầu quyền cao hơn mức cần thiết phải sử dụng. Cụ thể trong trường hợp này không quan tâm đến việc request permissions mà permissions sẽ được cung cấp tùy theo loged in user.
Cụ thể có 3 level cơ bản như sau (xem xét chỉnh sửa nếu cần thiết):
  • read - permission cho phép read private information
  • write - permission cho phép thêm, sửa và xóa metadata (bao gồm permission 'read')
  • delete - permission cho phép delete thông tin (bao gồm 'write' và 'read')

5. Authentication tokens

Mỗi authentication token được chỉ định riêng cho một user và một application tương ứng với application's api key, và chỉ được dùng tương ứng với application key này. Application có thể kiểm tra tình trạng của auth token bằng cách thực hiện API method auth.checkToken, method sẽ return tính hợp lệ của token cùng với user đã thực hiện authenticated (và permissions tương ứng nếu cần).
Authentication tokens có thể được thiết lập thời gian expire bởi user khi user thực hiện chứng thực với hệ thống. Chức năng này là chức năng nâng cao (có thể hide by default), có thể có 2 options là theo hour (1 hour) hoặc never. Chỉ duy nhất một auth token/app/user valid tại bất kỳ thời điểm nào. Application phải có trách nhiệm xử lý khi auth token expired, invalid và thực hiện renew.
Tất cả các API calls sử dụng auth token phải được signed (xem signing process).

6. Authentication frobs

Mỗi authentication frob sẽ tương ứng với một user và một application’s API key và chỉ có thể được sử dụng bởi application có API key này.
Giá trị của application frobs chỉ hợp lệ trong vòng 60 phút kể từ khi được tạo hoặc cho đến khi application thực hiện gọi auth.getToken.
Chỉ một application frob tương ứng với một application và một user được coi là hợp lệ tại bất kỳ thời điểm nào. Application phải có trách nhiệm xử lý khi auth token expired, invalid và thực hiện renew.

7. Signing

Tất cả các API call sử dụng auth token phải được ký tên (signed). Ngoài ra khi thực hiện các method auth.* methods và khi thực hiện chuyển hướng (redirections) tới trang chứng thực của hệ thống (system’s auth page) các yêu cầu này cũng phải thực hiện signing.
Như đã đề cập về hạn chế của message digest algorithms đặc biệt là MD5 hash, quá trình signing sẽ thực hiện khác với Flickr.
Các hướng có thể thực hiện là keep auth token secret bằng SSL, dùng auth token để signing hay coi auth token như là password bằng cách sử dụng HTTP digest authentication (RFC2617).
Một giải pháp khả thi là sử dụng một secure MAC implementations như HMAC-SHA1[8] (được hỗ trợ bởi hầu hết các programming language kể cả client và server side). Key của HMAC-SHA1 có thể sử dụng là shared secret.
Quá trình signing thực hiện theo các bước như sau:
  1. Thực hiện tạo danh sách các đối số thực (argument list) và sắp xếp theo alphabetical order dựa theo tên của tham số parameter name của từng argument. Có thể cần sẽ thực hiện normalize parameter (sẽ hướng dẫn cụ thể tham khảo Amazon Web Service, OAuth)
Ví dụ: foo = 1, bar = 2, baz = 3 sẽ được sắp xếp thành bar = 2, baz = 3, foo = 1
  1. Concatenate shared secret với các cặp argument dạng name/value (argument name/value pairs). Ví dụ: shared secret là BANANA concatenated argument list string là bar=2&baz=3&foo=1. Dùng shared secret BANANA làm key của HMAC. Kết quả có thể có format dạng base64 hoặc hexa string. Ví dụ: kết quả signature với giả sử format là base64 như sau Dcpc3Uf85y1VvZFs276KvGtum5Q=
  2. Append kết quả này vào argument list với parameter name là api_sig
Ví dụ: api_sig= Dcpc3Uf85y1VvZFs276KvGtum5Q=

8. Example cho non-web based application

  1. User nhấn login button trên application
  2. Application gọi background call tới server để nhận frob, call auth.getFrob ví dụ như sau http://www.company.com/services/rest/?method=auth.getFrob&api_key=987654321&api_sig=Dcpc3Uf85y1VvZFs276KvGtum5Q=
  3. System return frob ‘1a2b3c4d5e’
  4. Application launch system’s default browser với URL tạo được từ frob như sau http://www.company.com/services/auth/?api_key=987654321 &frob=1a2b3c4d5e&api_sig= Cdpc3Uf85y1VvZFs276KvGtum5Q=
  5. Nếu user chưa loged in vào web site, user sẽ được hỏi có thực hiện log in hay không.
· User có thể đăng nhập bằng log in form(username/password)
· User có thể chọn đăng nhập bằng OpenID,khi đó sẽ thực hiện theo flow authentication bằng OpenID
  1. Sau khi đăng nhập thành công user sẽ được hỏi có cho phép ứng dụng sử dụng các thông tin private hay không (trong trường hợp ứng dụng cụ thể thì private data là gì cần định nghĩa rõ)
  2. User chọn ‘Yes’ web site sẽ update auth database.
  3. User được hướng dẫn quay lại application và có thể đóng web page.
  4. User quay lại application và nhấn button ‘Continue’ (nút log in button trong bước log in có thể chuyển thành continue button)
  5. Application thực hiện background call tới auth.getToken, ví dụ http://www.company.com/services/rest/?method=auth.getToken&api_key=987654321&frob=1a2b3c4d5e&api_sig= Depc3Uf85y1VvZFs276KvGtum5Q=
  6. System trả về auth token ‘9765984’
  7. Application có thể thực hiện các background API call với auth token (signing với key là shared secret) ví dụ http://www.company.com/services/rest/?method=user.getProfile&api_token= 9765984&api_sig= Efpc3Uf85y1VvZFs276KvGtum5Q=

9. References