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/

https://www.c-sharpcorner.com/article/asp-net-mvc-oauth-2-0-rest-web-api-authorization-using-database-first-approach/

© 2019 Tüm Hakları Saklıdır. Codesenior.COM