امن سازی برنامههای ASP.NET Core توسط IdentityServer 4x - قسمت هفتم- امن سازی Web API
نویسنده: وحید نصیری
تاریخ: ۱۳۹۷/۰۶/۱۷ ۲۰:۲۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
namespace DNT.IDP
{
public static class Config
{
// api-related resources (scopes)
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource(
name: "imagegalleryapi",
displayName: "Image Gallery API",
claimTypes: new List<string> {"role" })
};
} AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Address,
"roles",
"imagegalleryapi"
}, namespace DNT.IDP
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddTestUsers(Config.GetUsers())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
} options.Scope.Add("imagegalleryapi"); dotnet add package IdentityServer4.AccessTokenValidation
using IdentityServer4.AccessTokenValidation;
namespace ImageGallery.WebApi.WebApp
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(defaultScheme: IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration["IDPBaseAddress"];
options.ApiName = "imagegalleryapi";
}); namespace ImageGallery.WebApi.WebApp
{
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication(); namespace ImageGallery.WebApi.WebApp.Controllers
{
[Route("api/images")]
[Authorize]
public class ImagesController : Controller
{ using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace ImageGallery.MvcClient.Services
{
public interface IImageGalleryHttpClient
{
Task<HttpClient> GetHttpClientAsync();
}
/// <summary>
/// A typed HttpClient.
/// </summary>
public class ImageGalleryHttpClient : IImageGalleryHttpClient
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _configuration;
private readonly IHttpContextAccessor _httpContextAccessor;
public ImageGalleryHttpClient(
HttpClient httpClient,
IConfiguration configuration,
IHttpContextAccessor httpContextAccessor)
{
_httpClient = httpClient;
_configuration = configuration;
_httpContextAccessor = httpContextAccessor;
}
public async Task<HttpClient> GetHttpClientAsync()
{
var currentContext = _httpContextAccessor.HttpContext;
var accessToken = await currentContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
if (!string.IsNullOrWhiteSpace(accessToken))
{
_httpClient.SetBearerToken(accessToken);
}
_httpClient.BaseAddress = new Uri(_configuration["WebApiBaseAddress"]);
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return _httpClient;
}
}
} <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Abstractions" Version="2.1.1.0" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="5.2.0.0" />
<PackageReference Include="IdentityModel" Version="3.9.0" />
</ItemGroup>
</Project>
{
"nbf": 1536394771,
"exp": 1536398371,
"iss": "https://localhost:6001",
"aud": [
"https://localhost:6001/resources",
"imagegalleryapi"
],
"client_id": "imagegalleryclient",
"sub": "d860efca-22d9-47fd-8249-791ba61b07c7",
"auth_time": 1536394763,
"idp": "local",
"role": "PayingUser",
"scope": [
"openid",
"profile",
"address",
"roles",
"imagegalleryapi"
],
"amr": [
"pwd"
]
}
An unhandled exception occurred while processing the request. HttpRequestException: Response status code does not indicate success: 401 (Unauthorized). System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
public async Task<IActionResult> Index()
{
var httpClient = await _imageGalleryHttpClient.GetHttpClientAsync();
var response = await httpClient.GetAsync("api/images");
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized ||
response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
return RedirectToAction("AccessDenied", "Authorization");
}
response.EnsureSuccessStatusCode(); namespace ImageGallery.WebApi.WebApp.Controllers
{
[Route("api/images")]
[Authorize]
public class ImagesController : Controller
{
[HttpGet()]
public async Task<IActionResult> GetImages()
{
var ownerId = this.User.Claims.FirstOrDefault(claim => claim.Type == "sub").Value; namespace ImageGallery.WebApi.Services
{
public class ImagesService : IImagesService
{
public Task<List<Image>> GetImagesAsync(string ownerId)
{
return _images.Where(image => image.OwnerId == ownerId).OrderBy(image => image.Title).ToListAsync();
} namespace ImageGallery.WebApi.WebApp.Controllers
{
[Route("api/images")]
[Authorize]
public class ImagesController : Controller
{
[HttpGet()]
public async Task<IActionResult> GetImages()
{
var ownerId = this.User.Claims.FirstOrDefault(claim => claim.Type == "sub").Value;
var imagesFromRepo = await _imagesService.GetImagesAsync(ownerId);
var imagesToReturn = _mapper.Map<IEnumerable<ImageModel>>(imagesFromRepo);
return Ok(imagesToReturn);
} namespace ImageGallery.WebApi.Services
{
public class ImagesService : IImagesService
{
public Task<bool> IsImageOwnerAsync(Guid id, string ownerId)
{
return _images.AnyAsync(i => i.Id == id && i.OwnerId == ownerId);
} namespace DNT.IDP
{
public static class Config
{
// api-related resources (scopes)
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource(
name: "imagegalleryapi",
displayName: "Image Gallery API",
claimTypes: new List<string> {"role" })
};
} namespace ImageGallery.WebApi.WebApp.Controllers
{
[Route("api/images")]
[Authorize]
public class ImagesController : Controller
{
[HttpPost]
[Authorize(Roles = "PayingUser")]
public async Task<IActionResult> CreateImage([FromBody] ImageForCreationModel imageForCreation)
{ var ownerId = User.Claims.FirstOrDefault(c => c.Type == "sub").Value; imageEntity.OwnerId = ownerId; // add and save. await _imagesService.AddImageAsync(imageEntity);
@if(User.IsInRole("PayingUser"))
{
<li><a asp-area="" asp-controller="Gallery" asp-action="AddImage">Add an image</a></li>
<li><a asp-area="" asp-controller="Gallery" asp-action="OrderFrame">Order a framed picture</a></li>
} namespace ImageGallery.MvcClient.WebApp.Controllers
{
[Authorize]
public class GalleryController : Controller
{
[Authorize(Roles = "PayingUser")]
public IActionResult AddImage()
{
return View();
} [HttpPost] [Authorize(Roles = "PayingUser")] [ValidateAntiForgeryToken] public async Task<IActionResult> AddImage(AddImageViewModel addImageViewModel)
public async Task<IActionResult> Index()
{
var httpClient = await _imageGalleryHttpClient.GetHttpClientAsync();
var response = await httpClient.GetAsync("api/images");
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized ||
response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
return RedirectToAction("AccessDenied", "Authorization");
}
response.EnsureSuccessStatusCode();