C# Web Api Bearer Token Tabanlı Authentication İşlemi
19-10-2019Öncelikle Nuget kütüphanelerinin kurulması gerekir:
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2 Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.0 Install-Package Microsoft.AspNet.Identity.Owin -Version 2.0.1 Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.0.1 Install-Package Microsoft.Owin.Security.OAuth -Version 2.1.0 Install-Package Microsoft.Owin.Cors -Version 2.1.0
Daha sonra Startup.cs sınıfı eklenir:
using System;
using System.Web.Http;
using MapToner.Helpers;
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using Owin;
[assembly: OwinStartup(typeof(MapToner.Startup))]
namespace MapToner
{
public class Startup
{
public static string PublicClientId { get; private set; }
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
ConfigureAuth(app);
WebApiConfig.Register(config);
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureAuth(IAppBuilder app)
{
// Configure the application for OAuth based flow
PublicClientId = "self";
var oAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new AppOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthOptions);//Oauth2 ayarlarinin yapilmasini saglar
//Http request header'daki bearer token olup olmadigini anlamak icin kullanilir.
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
}
WebApiConfig.cs sınıfı aşağıdaki gibi olursa çok iyi olur:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
ConfigureJsonResponse(config);
}
private static void ConfigureJsonResponse(HttpConfiguration config)
{
//Removes XML response, return JSON response
var contractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
var jsonFormatter = config.Formatters.OfType<jsonmediatypeformatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = contractResolver;
// Adding JSON type web api formatting.
config.Formatters.Clear();
config.Formatters.Add(jsonFormatter);
}
}
</jsonmediatypeformatter>
Son olarak AppOAuthProvider.cs sınıfı tanımlanır:
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using MapToner.EntityFramework;
using MapToner.Models;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
namespace MapToner.Helpers
{
/// <summary>
/// Application OAUTH Provider class.
/// </summary>
public class AppOAuthProvider : OAuthAuthorizationServerProvider
{
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Initialization.
var user = await new LoginHelper().Login(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "Böyle bir kullanıcı bulunamadı");
new LogHelper().SaveUserLog(HttpContext.Current.Request.Browser.Browser,
HttpContext.Current.Request.UserHostAddress);
return;
}
var representative = new UserHelper().GetUser((int)user.temsilci_id);
new LogHelper().SaveUserLog(HttpContext.Current.Request.Browser.Browser,
HttpContext.Current.Request.UserHostAddress, user.id);
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, context.UserName),
new Claim(ClaimTypes.NameIdentifier, user.id.ToString())
};
var oAuthClaimIdentity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
var ticket = new AuthenticationTicket(oAuthClaimIdentity, CreateProperties(user, representative));
context.Validated(ticket);
}
/// <summary>
/// Accesss token generate olurken yani /token linkine post edildiginde CreateProperties metodunun donderdigi Map degeri json response da ekstra
/// parametre olarak gonderilir.
/// </summary>
/// <param name="user"></param>
/// <param name="representative"></param>
/// <returns></returns>
public static AuthenticationProperties CreateProperties(User user,User representative)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{"full_name", user.adi_soyadi},
{"phone", user.tel},
{"email", user.mail},
{"user_login", "evet"},
{"user_guid", user.GUID},
{"iskonto_id", user.iskonto_id.ToString()},
{"representative_id", user.temsilci_id.ToString()},
{"representative_full_name", representative.adi_soyadi},
{"representative_phone", representative.tel.Replace(" ","")},
{"representative_email", representative.mail},
{"is_current_payment_active", user.cari=="1"?"true":"false"},
};
return new AuthenticationProperties(data);
}
/// <summary>
/// CreateProperties metodundaki parametrelere ek olarak baska parametreler eklemek icin kullanilabilir. Yine ayni sekilde /token linkine post edilince
/// post sonucunda donen json da bu parametreler yer alacaktir.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (var property in context.Properties.Dictionary)
context.AdditionalResponseParameters.Add(property.Key, property.Value);
return Task.FromResult<object>(null);
}
/// <summary>
/// Client Id leri validate etmek icin kullanilir. Bizim uygulamamızda 1 tane olduğu için context.Validated() demek yeterli olacaktır.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
if (context.ClientId == null)
context.Validated();
return Task.FromResult<object>(null);
}
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
context.Validated(newTicket);
return Task.FromResult<object>(null);
}
}
}
Daha fazla bilgi için:
https://blogs.perficient.com/2017/06/11/token-based-authentication-in-web-api-2-via-owin/