2017-01-24

Azure Active Directory - Part 13 ( Azure AD 與 ASP.NET Web API 整合)

Azure Active Directory - Part 11 ( Azure AD 與 ASP.NET MVC 整合),介紹 ASP.NET MVC 與 Azure AD 的整合, Azure Active Directory - Part 12 ( 使用 Javascript - adal.js 取得使用者資料),看了該如何使用 Javascript 配合 Graph API 來取得使用者資料,今天我們來看另一個開發上的常見範例:如何使用 Javascript 存取 Azure AD 保護的 Web API。


文章大綱

  1. 建立 ASP.NET Web API 應用程式
  2. 在 Azure AD 上註冊應用程式
  3. 設定 ASP.NET Web API 應用程式
  4. 前端 Javascript 取得資料
  5. 心得

建立 ASP.NET Web API 應用程式

  1. 建立 ASP.NET Web API 專案
    • web 專案 template
    • .net framework
    • ASP.NET Web Application
    • project Name

      1API

    • empty --> Web API

      2create

  2. 加入 owin
    • Microsoft.Owin.Security.ActiveDirectory
    • Microsoft.Owin.Host.SystemWeb

      3pkgconsole

      • 可使用 NuGet GUI (以下使用 Package Manager Console)
      Install-Package Microsoft.Owin.Security.ActiveDirectory
      Install-Package Microsoft.Owin.Host.SystemWeb
      
  3. 加入 Startup.cs
    • 在專案根目錄加入 Startup.cs 檔案
    • 加入方式有兩個,擇一即可
      • 1.專案按右鍵 --> Add --> New Item..

        4newitem

        • 搜尋 OWIN --> OWIN Startup class --> Name

          5newsrartup

      • 2.專案按右鍵 --> Add --> OWIN Startup class

        6OWINCLASS

        • 指定檔案名稱

          7nameing

    • 修改 Startup.cs
      • 將 class 加上 partial
        • public class Startup --> public partial class Startup
      • Configuration 中 call ConfigureAuth 並傳入 IAppBuilder
        • ConfigureAuth(app);
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                ConfigureAuth(app);
            }
        }
        
  4. 加入 Startup.Auth.cs
    • App_Start 目錄加入 Startup.Auth.cs 檔案(加入方式同上)
      • namespace 需與根目錄 Startup.cs 相同
    • 修改 Startup.Auth.cs
      • 將 class 加上 partial
        • public class Startup --> public partial class Startup
      • 加入 audience,tenant
        private static string audience = ConfigurationManager.AppSettings["ida:Audience"];
        private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
        
      • 加入 ConfigureAuth 方法
        public void ConfigureAuth(IAppBuilder app)
        {
            app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Tenant = tenant,
                TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = true,
                    ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
                },
            });
        }
        
      • 需要 using Microsoft.Owin.Security.ActiveDirectory,System.Configuration
  5. 加入 ValuesController
    • Controllers 資料夾右鍵 --> Add --> Controller... >8addcontroller
      • Web API 2 Controller -Empty

        9controllertype

      • Namig Controller

        10namingcontroller

    • 加上 Get action 及隨意可識別的回傳值
      public string Get()
      {
          return "ok";
      }
      

在 Azure AD 上註冊應用程式

  1. 登入 Azure 入口網站
  2. Azure Active Directory

    1aad

  3. 應用程式註冊 --> 加入

    13register

  4. 填寫應用程式資訊

    14APPINFO

    • 名稱
      • 至少需有四個字元

        15NAME

    • 應用程式類型

      16type

      • WEB
      • 可安裝的應用程式
    • 登入 URL

      17url

      • 1.專案按 F4 開啟 Project Properties --> Url

        18properties

      • 2.專案右鍵 --> Properties --> Web --> Project Url

        19project

        20url

設定 ASP.NET Web API 應用程式

  1. Web.config 加入設定值
    <add key="ida:Tenant" value="" />
    <add key="ida:Audience" value="" />
    
    • ida:Tenant
      • e.g. contoso.onmicrosoft.com

        22tenant

    • ida:Audience
      • Azure 入口網站中的應用程式識別碼

        22clientid

  2. 加入驗證
    • 直接在需要驗證 Controller 或是 Action 上加上 [Authorize]

前端 Javascript 取得資料

  1. 引用 adal.js

    <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.11/js/adal.min.js"></script
  2. 設定基本資訊

    // 設定 adal 所需資訊
    var _config = {
        tenant: '{網域名稱}',
        clientId: '{app id}'
    };
    
    • tenant
      • e.g. contoso.onmicrosoft.com >22tenant
    • clientId
      • 應用程式識別碼
      • e.g. 82692da5-a86f-44c9-9d53-2f88d52b478b >21clientID
  3. 初始化驗證所需資訊

    var authContext = new AuthenticationContext({
        tenant: _config.tenant,
        clientId: _config.clientId,
        postLogoutRedirectUri: window.location
    });
    
  4. 取得 token

    if (authContext.isCallback(window.location.hash)) {
        // 處理要求 token 後的回應
        authContext.handleWindowCallback();
        var err = authContext.getLoginError();
        if (err) {
            $('#result').html('ERROR:\n\n' + err);
        }
    } else {
        // 檢查是否登入
        var user = authContext.getCachedUser();
        if (user) {
            $('#username').html('Signed in as: ' + user.userName);
            $('#result').html('Getting access token...');
    
            // 取得可以用來存取 web API 的 token
            authContext.acquireToken(
                 _config.clientId,
                function (error, token) {
                    if (error || !token) {
                        // TODO: Handle error obtaining access token
                        $('#result').html('ERROR:\n\n' + error);
                        return;
                    }
                    // 使用 token 去拿資料
                    getData(token);
                }
            );
        } else {
            $('#username').html('Not signed in.');
        }
    }
    
  5. 使用 token 取得使用者資料

    var getData = function (access_token) {
        $('#result').html('Calling API...');
        $.ajax({
                    url: '/api/values',
                    method: 'GET',
                    headers: {
                        'Authorization': 'Bearer ' + access_token
                    }
                })
                .success(function (data) {
                    $('#result')
                        .html(
                            //JSON.stringify(JSON.parse(jqXHR.responseText), null, '  '));
                            JSON.stringify(data, null, '  '));
                })
                .error(function(data) {
                    console.log(data);
                    $('#result').html('ERROR:\n\n' + JSON.stringify(data, null, '  '));
                })
            ;
    }
    
  6. 完整程式碼

    • 前端程式 請參考 adal.js-sample
    • api 內容如下
      [Authorize]
      public class ValuesController : ApiController
      {
          public string Get()
          {
              return "ok";
          }
      }
      

心得

這篇在實作時卡了好幾天,有些名稱的命名很像,在文件上各版本間還會出現衝突;微軟官網似乎是比較愛 SPA,Javascript 實作很難找(我是沒找到);相關文件存在很多地方,不同入口會看到不同內容XD

參考資料

  1. 使用 Azure AD 的持有者權杖來保護 Web API
  2. Add authentication token to AJAX call for a Web API secured using Azure Active Directory authentication
  3. Active Directory Authentication Library (ADAL) for JavaScript
  4. adal.js-sample

沒有留言:

張貼留言