image

Предисловие


Завершающая работа в цикле по работе с Azure B2C. В этой статье я расскажу о том, как подключить аутентификацию к бэкэнду на .NET Core 3.

Ссылки на связанные посты


ШАГ 1


В файле Startup.cs в методе ConfigureServices необходимо добавить следующий код:

  using Microsoft.AspNetCore.Authentication.JwtBearer;

  public void ConfigureServices(IServiceCollection services)
  {
    // .....
    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        // ClientID вашего приложения Azure AD B2C
        options.Audience = "777aaa77a-7a77-7777-bb77-8888888aabc";
        // Найти issuer можно во вкладке "Обзор". Для этого нажмите кнопку
        // "Конечные точки". В конец поставьте название политики,
        // которую вы используете (B2C_1A_signup_signin).
        options.Authority = "https://antekesd.b2clogin.com/antekesd.onmicrosoft.com/B2C_1A_signup_signin";
        options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
        {
            // Укажите, кто создает токен. Для этого перейдите в ваше приложение на
            // Azure AD B2C и во вкладке обзор - скопируйте и замените teanat-id
            // на "Идентификатор каталога"
            ValidateIssuer = true,
            ValidIssuer = "https://antekesd.b2clogin.com/teanat-id/v2.0/"
        };
    });
    // Добавляем политику, по которой будет проверять поступающие запросы
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AuthOnly", policy => policy.RequireAuthenticatedUser());
    });
    // .....
  }

ШАГ 2


В этом же файле, в методе Configure необходимо добавить UseAuthentication и UseAuthorization. Они обязательно должны быть между UseRouting и UseEndpoints, как показано в примере ниже:

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  {
    // .....
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller}/{action=Index}/{id?}");
    });
    // .....
  }

ШАГ 3


Теперь все готово, осталось только добавить проверку на контроллер. Для этого в любом контроллере добавьте,
[Authorize(Policy = "AuthOnly")]

как показано в примере ниже:

    [Authorize(Policy = "AuthOnly")]
    [Route("api/[controller]")]
    [ApiController]
    public class ClientController : ControllerBase
    {
        private readonly ClientService _clientService;
        public ClientController(ClientService clientService)
        {
            _clientService = clientService;
        }

        [HttpGet()]
        public async Task<IActionResult> GetClientList()
        {
            try
            {
                var result = await _clientService.GetClientsList();
                return Ok(result);
            }
            catch (HttpRequestException httpException)
            {
                throw httpException;
            }
        }
    }

Теперь, каждый раз когда будет приходить запрос с клиента — бэкэнд будет проверять JWT token. О токенах можно почитать тут.

Пример заголовка запроса:

  {
    Accept: application/json, text/plain, */*
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en,ru;q=0.9,en-GB;q=0.8,en-US;q=0.7
    Authorization: Bearer jwtIdTokenFromMSAL
    Connection: keep-alive
    Host: yourhost.azurewebsites.net
    Pragma: no-cache
    Referer: https://yourhost.azurewebsites.net/
    Sec-Fetch-Dest: empty
    Sec-Fetch-Mode: cors
    Sec-Fetch-Site: same-origin
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 Edg/83.0.478.45
  }

Отправка запроса с одного сервера на другой


Иногда возникает ситуация, когда приложение использует не один бэкэнд. Тогда возникает необходимость отправить запрос с бэка на бэк. Для этого нам нужно создать HTTP клиент и добавить в него токен. Вот как это делается

ШАГ 1


Создаем сервис, который будет слать запросы.

  using System.Net.Http;
  using System.Net.Http.Headers;
  using Microsoft.AspNetCore.Http;

  public class ClientService
    {
        // Создаем HttpClient 
        HttpClient Client { get;  }
        public ClientService(HttpClient client, IHttpContextAccessor httpContextAccessor)
        {
            // Говорим куда слать запрос
            client.BaseAddress = new Uri("https://another-server.azurewebsites.net/api/");
            string _ContentType = "application/json";
            // Говорим что отправлять будем JSON
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_ContentType));
            // Добавляем JWT Токен
            client.DefaultRequestHeaders.Add("Authorization", (string)httpContextAccessor.HttpContext.Request.Headers["Authorization"]);
            Client = client;
        }

        public async Task<string> GetClientsList()
        {
            // Отправляем запрос
            var response = await Client.GetAsync("url-to-another-endpoint");
            if (response.StatusCode != HttpStatusCode.OK)
            {
                return response.StatusCode.ToString();
            }
            string result = await response.Content.ReadAsStringAsync();
            return result;
        }
    }

ШАГ 2


Добавляем Http client созданному сервису. Для этого нужно в файле Startup.cs добавить следующий код:

  public void ConfigureServices(IServiceCollection services)
  {
    // ...
    services.AddHttpClient<ClientService>();
    // ...
  }

Заключение


Теперь все готово! Вы можете отправлять запрос с клиента на сервер и с сервера на другой сервер.

Спасибо за внимание!