共用方式為


驗證及保護 Web 延伸模組

Azure DevOps 服務 |Azure DevOps Server |Azure DevOps Server 2022

本文僅適用於 Web 延伸模組的驗證和安全性,而不是管線工作延伸模組或服務端點延伸模組。 針對這些工作,您可以使用 發佈到 Azure Service Bus 的任務

從擴充套件呼叫 REST API

大部分的擴充功能都需要代表目前的用戶呼叫 Azure DevOps REST API。

  • 如果您使用提供的 JavaScript REST clients,系統會自動為您處理驗證。 這些用戶端會向核心 SDK 要求存取令牌,並在要求的授權標頭中設定它。

  • 如果您未使用提供的用戶端,您必須向 Core SDK 申請令牌,並在您的請求中將其設定在 [Authorization] 標頭。

    import * as SDK from "azure-devops-extension-sdk";
    import { getAccessToken } from "azure-devops-extension-sdk";
    
    SDK.init();
    
    getAccessToken().then((token) => {
        // Format the auth header
        const authHeader = `Bearer ${token}`;
    
        // Add token as an Authorization header to your request
        console.log(authHeader);
    });
    

小提示

請參閱使用 Azure DevOps 擴充功能 SDK的最新擴充功能開發檔。

驗證對你的服務的請求

常見的情境是從擴充套件呼叫後端服務。 若要確認這些呼叫來自您在 Azure DevOps 中執行的擴充功能,以及驗證目前使用者和其他內容資訊,則會將特殊類型的令牌提供給您的延伸模組。 此令牌包含呼叫端的相關資訊,以及您可以驗證的簽名,以確保請求來自您的擴充功能。

取得擴充功能的金鑰

當擴充功能發佈時所產生的唯一密鑰,可用來驗證從你的擴充功能提出的要求的真實性。

若要取得此金鑰,請移至 延伸模組管理入口網站,以滑鼠右鍵按兩下 已發佈的延伸模組,然後選取 [憑證 ]。

key

警告

延伸模組中的範圍變更會導致憑證變更。 如果您變更範圍,則需要新的延伸模組密鑰。

產生令牌以提供給您的服務

  1. Core SDK getAppToken 方法會傳回承諾,當解析時,會包含以延伸模組憑證簽署的令牌。

    import * as SDK from "azure-devops-extension-sdk";
    import { getAppToken } from "azure-devops-extension-sdk";
    
    SDK.init();
    
    getAppToken().then((token) => {
    // Add token to your request
    console.log(token);
    });
    
  2. 將此令牌傳遞至您的服務做為查詢參數或要求標頭。

剖析和驗證令牌

以下是剖析令牌的範例。 首先,從發行者頁面下載並儲存延伸模組的秘密。 此秘密必須可供您的應用程式使用。

.NET Framework

執行下列工作以新增一個參考,以取得要編譯的範例。

開啟 NuGet 套件管理員,並將參考新增至 System.IdentityModel.Tokens.Jwt。 此範例是使用此套件 6.8.0 版所建置。

using System;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;

namespace TokenSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string secret = ""; // Load your extension's secret
            string issuedToken = ""; // Token you are validating
                
            var validationParameters = new TokenValidationParameters()
            {
                IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(secret)),
                ValidateIssuer = false,
                RequireSignedTokens = true,
                RequireExpirationTime = true,
                ValidateLifetime = true,
                ValidateAudience = false,
                ValidateActor = false
            };

            SecurityToken token = null;
            var tokenHandler = new JwtSecurityTokenHandler();
            var principal = tokenHandler.ValidateToken(issuedToken, validationParameters, out token);
            
            // Use the principal object as needed
            Console.WriteLine(principal.Identity.Name);
        }
    }
}

.NET Core - WebAPI

執行下列工作以新增一個參考,使此範例能夠編譯。

開啟 NuGet 套件管理員,並將參考新增至 System.IdentityModel.Tokens.Jwt。 此範例是使用此套件 5.1.4 版所建置。

Startup.cs

using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;

namespace TokenSample.Core.API
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            string _secret = "ey9asfasdmax..<the secret key downloaded from the Azure DevOps Services publisher page>.9faf7eh";
        
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                    .AddJwtBearer((o) =>
                    {
                        o.TokenValidationParameters = new TokenValidationParameters()
                        {
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret)),
                            ValidateIssuer = false,
                            ValidateAudience = false,
                            ValidateActor = false,
                            RequireSignedTokens = true,
                            RequireExpirationTime = true,
                            ValidateLifetime = true
                        };    
                    });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseAuthentication();
            app.UseAuthorization();
            app.UseRouting();
            app.UseStaticFiles();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

API 控制器:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
[Authorize]
public class SampleLogicController : ControllerBase
{
   // ...
}