身份验证和安全性

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

本文仅适用于 Web 扩展,而不适用于管道任务扩展或服务终结点扩展。 对于这些任务,可以使用“发布”来Azure 服务总线任务

提示

查看有关使用 Azure DevOps 扩展 SDK 进行扩展开发的最新文档。

从扩展调用 REST API

大多数扩展都需要代表当前用户调用 Azure DevOps REST API。

  • 如果使用提供的 JavaScript REST clients身份验证,则会自动为你处理身份验证。 这些客户端会自动从核心 SDK 请求访问令牌,并将其设置为请求的授权标头。

  • 如果不使用提供的客户端,则需要从 Core SDK 请求的授权标头中请求令牌并将其设置为:

    VSS.require(["VSS/Authentication/Services"],
        function (VSS_Auth_Service) {
            VSS.getAccessToken().then(function(token){
                // Format the auth header
                var authHeader = VSS_Auth_Service.authTokenManager.getAuthorizationHeader(token);
    
                // Add token as an Authorization header to your request
            });
        });
    

对服务的请求进行身份验证

常见方案是从扩展调用后端服务。 若要验证这些调用是否来自 Azure DevOps 中运行的扩展,并验证当前用户(和其他上下文信息)的真实性,扩展可以使用特殊类型的令牌。 此令牌包含有关谁正在调用的信息,以及一个签名,你可以验证该签名以了解请求是否来自你的扩展。

获取扩展的密钥

扩展的唯一密钥(在发布扩展时生成)可用于验证从扩展发出的请求的真实性。

若要获取此密钥,请右键单击已发布的 扩展 并选择“ 证书”。

key

警告

扩展中的作用域更改会导致证书更改。 如果对范围进行更改,则需要新的扩展密钥。

生成令牌以提供给服务

  1. Core SDK getAppToken 方法返回一个承诺,即解析后,包含使用扩展证书签名的令牌。

    VSS.getAppToken().then(function(token){
        // Add token to your request
    });
    
  2. 将此令牌作为查询参数或请求标头传递给服务。

分析和验证令牌

下面是分析令牌的示例。 首先下载并存储扩展的机密。 可以从发布者页面获取此信息。 此机密需要可供应用程序使用。

.NET Framework

必须添加 1 个引用才能使此示例进行编译。

  1. 打开 NuGet 程序包管理器并添加对 System.IdentityModel.Tokens.Jwt 的引用。 此示例是使用此包版本 5.2.2 生成的。
using System.Collections.Generic;
using System.ServiceModel.Security.Tokens;
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.UTF8Encoding.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);
		}
	}
}

.NET Core - WebAPI

必须添加 1 个引用才能使此示例进行编译。

  1. 打开 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.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.AddMvc();

            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, IHostingEnvironment env)
        {
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseMvc();
            app.UseStaticFiles();
        }
    }
}

API 控制器:

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