Возможно ли защитить область (web api) и аутентифицировать клиента (web app mvc) в одном проекте? - PullRequest
0 голосов
/ 03 апреля 2019

Доброе утро, мне нужно иметь в одном проекте и веб-API, и веб-приложение MVC.Веб-API должен быть защищен с помощью токена-носителя, а веб-приложение mvc должно быть аутентифицировано через идентификационный сервер.Возможно ли защитить область и клиента в одном проекте?

Я думаю, что мне нужно сделать что-то подобное при запуске

//this to protect scope api1
services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "http://localhost:5000/";
        options.RequireHttpsMetadata = false;

        options.Audience = "api1";
    });

//this to authenticate mvc client
services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
    options.AccessDeniedPath = "/account/denied";
})
.AddOpenIdConnect("oidc", options =>
{                
    options.SignInScheme = "Cookies";

    options.Authority = "http://localhost:5000",
    options.RequireHttpsMetadata = false;

    options.ResponseType = "id_token token";
    options.ClientId = "mvc-implicit";
    options.SaveTokens = true;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("api1");    
    options.GetClaimsFromUserInfoEndpoint = true;    
    options.ClaimActions.MapJsonKey("role", "role", "role");
    options.TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "role"
    };                
});

Теперь я должен вызвать свой Api1 с помощью client_credential свнешний клиент.Но он возвращает меня на странице входа.

Можно ли делать то, что я хочу?Защищенный клиент WebApi и MVC-клиент, прошедший проверку подлинности в одном проекте?

1 Ответ

0 голосов
/ 04 апреля 2019

Теперь я должен вызвать свой Api1, используя client_credential с внешним клиентом. Но он возвращает меня на странице входа.

Кажется, вы неправильно поняли сценарий. Ваше MVC-приложение является клиентом и является приложением-ресурсом, которое защищено Identity Server (в Config.cs):

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiResource("api1", "My API")
    };
 }

Я предполагаю, что в вашем приложении MVC есть контроллер API:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET: api/Values
    [HttpGet]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

И у вас есть конфигурация для защиты действий API с помощью AddJwtBearer:

services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
    options.Authority = "http://localhost:5000/";
    options.RequireHttpsMetadata = false;

    options.Audience = "api1";
});

Это означает, что любой запрос на доступ к действию Get должен иметь заголовок носителя аутентификации с добавлением токена доступа, токен доступа выдается сервером идентификации (конечная точка http://localhost:5000/), а аудитория - api1.

Теперь ваш другой клиент может использовать поток учетных данных клиента для получения токена доступа для доступа к вашему веб-приложению:

var client = new HttpClient();

var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

// request token
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address = disco.TokenEndpoint,
    ClientId = "client",
    ClientSecret = "secret",

    Scope = "api1"
});

И назовите ваши защищенные действия:

var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);

var response = await apiClient.GetAsync("http://localhost:64146/api/values");
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var content = await response.Content.ReadAsStringAsync();
    Console.WriteLine(JArray.Parse(content));
}

Таким образом, он не будет перенаправлять на страницу входа, поскольку учетные данные клиента фактически отправляют HTTP-запрос POST, чтобы получить токен доступа с учетными данными приложения. В этом сценарии нет страницы входа.

...