ASP.NET कोर वेब एपीआई प्रमाणीकरण


98

मैं अपनी वेब सेवा में प्रमाणीकरण स्थापित करने के तरीके से जूझ रहा हूं। सेवा ASP.NET कोर वेब एपीआई के साथ निर्मित है।

मेरे सभी क्लाइंट (WPF एप्लिकेशन) को वेब सेवा संचालन को कॉल करने के लिए समान क्रेडेंशियल्स का उपयोग करना चाहिए।

कुछ शोध के बाद, मैं बुनियादी प्रमाणीकरण के साथ आया - HTTP अनुरोध के शीर्ष लेख में एक उपयोगकर्ता नाम और पासवर्ड भेज रहा हूं। लेकिन घंटों के शोध के बाद, यह मुझे लगता है कि बुनियादी प्रमाणीकरण ASP.NET कोर में जाने का तरीका नहीं है।

मेरे द्वारा पाए गए अधिकांश संसाधन OAuth या कुछ अन्य मिडलवेयर का उपयोग करके प्रमाणीकरण को लागू कर रहे हैं। लेकिन यह मेरे परिदृश्य के लिए, साथ ही ASP.NET कोर के आइडेंटिटी भाग का उपयोग करता हुआ प्रतीत होता है।

तो मेरे लक्ष्य को प्राप्त करने का सही तरीका क्या है - ASP.NET कोर वेब सेवा में उपयोगकर्ता नाम और पासवर्ड के साथ सरल प्रमाणीकरण?

अग्रिम में धन्यवाद!

जवाबों:


75

आप एक मिडलवेयर लागू कर सकते हैं जो बेसिक ऑथेंटिकेशन को हैंडल करता है।

public async Task Invoke(HttpContext context)
{
    var authHeader = context.Request.Headers.Get("Authorization");
    if (authHeader != null && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
    {
        var token = authHeader.Substring("Basic ".Length).Trim();
        System.Console.WriteLine(token);
        var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token));
        var credentials = credentialstring.Split(':');
        if(credentials[0] == "admin" && credentials[1] == "admin")
        {
            var claims = new[] { new Claim("name", credentials[0]), new Claim(ClaimTypes.Role, "Admin") };
            var identity = new ClaimsIdentity(claims, "Basic");
            context.User = new ClaimsPrincipal(identity);
        }
    }
    else
    {
        context.Response.StatusCode = 401;
        context.Response.Headers.Set("WWW-Authenticate", "Basic realm=\"dotnetthoughts.net\"");
    }
    await _next(context);
}

यह कोड asp.net कोर के बीटा संस्करण में लिखा गया है। आशा करता हूँ की ये काम करेगा।


1
आपके उत्तर के लिए धन्यवाद! यह वही है जो मैं देख रहा था - मूल प्रमाणीकरण के लिए एक सरल समाधान।
फेलिक्स

1
क्रेडेंशियलस्ट्रिंग का उपयोग करने के कारण इस कोड में एक बग है। एसप्लिट (':') - यह उन पासवर्डों को सही ढंग से संभाल नहीं पाएगा जिनमें एक बृहदान्त्र होता है। फेलिक्स द्वारा जवाब में कोड इस मुद्दे से ग्रस्त नहीं है।
फिल डेनिस

111

अब, मुझे सही दिशा में इंगित करने के बाद, यहाँ मेरा पूरा समाधान है:

यह मिडिलवेयर क्लास है जिसे हर आने वाले अनुरोध पर निष्पादित किया जाता है और यदि अनुरोध में सही क्रेडेंशियल्स हैं तो जांच करता है। यदि कोई क्रेडेंशियल मौजूद नहीं है या यदि वे गलत हैं, तो सेवा तुरंत 401 अनधिकृत त्रुटि के साथ जवाब देती है ।

public class AuthenticationMiddleware
{
    private readonly RequestDelegate _next;

    public AuthenticationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        string authHeader = context.Request.Headers["Authorization"];
        if (authHeader != null && authHeader.StartsWith("Basic"))
        {
            //Extract credentials
            string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
            Encoding encoding = Encoding.GetEncoding("iso-8859-1");
            string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));

            int seperatorIndex = usernamePassword.IndexOf(':');

            var username = usernamePassword.Substring(0, seperatorIndex);
            var password = usernamePassword.Substring(seperatorIndex + 1);

            if(username == "test" && password == "test" )
            {
                await _next.Invoke(context);
            }
            else
            {
                context.Response.StatusCode = 401; //Unauthorized
                return;
            }
        }
        else
        {
            // no authorization header
            context.Response.StatusCode = 401; //Unauthorized
            return;
        }
    }
}

मिडिलवेयर एक्सटेंशन को सेवा स्टार्टअप क्लास के कॉन्फ़िगर विधि में बुलाया जाना चाहिए

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseMiddleware<AuthenticationMiddleware>();

    app.UseMvc();
}

और बस यही! :)

.Net कोर और प्रमाणीकरण में मिडलवेयर के लिए एक बहुत अच्छा संसाधन यहाँ पाया जा सकता है: https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/


4
संपूर्ण समाधान पोस्ट करने के लिए धन्यवाद। हालाँकि, मुझे 'संदर्भ जोड़ना होगा। Response.Headers.Add ("WWW-Authenticate", "मूल क्षेत्र = \" realm \ "");' ब्राउज़र को क्रेडेंशियल का अनुरोध करने के लिए 'कोई प्राधिकरण हेडर' अनुभाग नहीं।
m0n0ph0n

यह प्रमाणीकरण कितना सुरक्षित है? क्या होगा यदि कोई व्यक्ति अनुरोध हेडर को सूँघता है और उपयोगकर्ता नाम / पासवर्ड प्राप्त करता है?
बेवर सलाह

5
@BewarSalah आप https पर समाधान इस तरह की सेवा करनी पड़ेगी
वाल

2
कुछ नियंत्रकों को अनाम की अनुमति देनी चाहिए। यह मिडलवेयर सॉल्यूशन उस स्थिति में विफल हो जाएगा क्योंकि यह प्रत्येक अनुरोध में प्राधिकरण हेडर के लिए जाँच करेगा।
कार्तिक

28

केवल विशिष्ट नियंत्रकों के लिए इसका उपयोग करने के लिए उदाहरण के लिए इसका उपयोग करें:

app.UseWhen(x => (x.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)), 
            builder =>
            {
                builder.UseMiddleware<AuthenticationMiddleware>();
            });

22

मुझे लगता है कि आप JWT (Json Web टोकन) के साथ जा सकते हैं।

सबसे पहले आपको पैकेज System.IdentityModel.Tokens.Jwt स्थापित करना होगा:

$ dotnet add package System.IdentityModel.Tokens.Jwt

आपको टोकन जेनरेशन और ऑथेंटिकेशन के लिए एक कंट्रोलर को इस तरह जोड़ना होगा:

public class TokenController : Controller
{
    [Route("/token")]

    [HttpPost]
    public IActionResult Create(string username, string password)
    {
        if (IsValidUserAndPasswordCombination(username, password))
            return new ObjectResult(GenerateToken(username));
        return BadRequest();
    }

    private bool IsValidUserAndPasswordCombination(string username, string password)
    {
        return !string.IsNullOrEmpty(username) && username == password;
    }

    private string GenerateToken(string username)
    {
        var claims = new Claim[]
        {
            new Claim(ClaimTypes.Name, username),
            new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()),
            new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(1)).ToUnixTimeSeconds().ToString()),
        };

        var token = new JwtSecurityToken(
            new JwtHeader(new SigningCredentials(
                new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Secret Key You Devise")),
                                         SecurityAlgorithms.HmacSha256)),
            new JwtPayload(claims));

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

उसके बाद नीचे की तरह दिखने के लिए Startup.cs वर्ग को अपडेट करें:

namespace WebAPISecurity
{   
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(options => {
            options.DefaultAuthenticateScheme = "JwtBearer";
            options.DefaultChallengeScheme = "JwtBearer";
        })
        .AddJwtBearer("JwtBearer", jwtBearerOptions =>
        {
            jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Secret Key You Devise")),
                ValidateIssuer = false,
                //ValidIssuer = "The name of the issuer",
                ValidateAudience = false,
                //ValidAudience = "The name of the audience",
                ValidateLifetime = true, //validate the expiration and not before values in the token
                ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
            };
        });

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAuthentication();

        app.UseMvc();
    }
}

और बस यही है, अब जो कुछ बचा है, उसे [Authorize]कंट्रोलर्स या ऐक्टिविटीज पर जगह चाहिए।

यहाँ एक पूर्ण सीधे फॉरवर्ड ट्यूटोरियल का लिंक दिया गया है।

http://www.blinkingcaret.com/2017/09/06/secure-web-api-in-asp-net-core/


9

मैं लागू कर दिया है BasicAuthenticationHandlerबुनियादी प्रमाणीकरण के लिए ताकि आप standart विशेषताओं के साथ उपयोग कर सकते हैं Authorizeऔर AllowAnonymous

public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var authHeader = (string)this.Request.Headers["Authorization"];

        if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
        {
            //Extract credentials
            string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
            Encoding encoding = Encoding.GetEncoding("iso-8859-1");
            string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));

            int seperatorIndex = usernamePassword.IndexOf(':', StringComparison.OrdinalIgnoreCase);

            var username = usernamePassword.Substring(0, seperatorIndex);
            var password = usernamePassword.Substring(seperatorIndex + 1);

            //you also can use this.Context.Authentication here
            if (username == "test" && password == "test")
            {
                var user = new GenericPrincipal(new GenericIdentity("User"), null);
                var ticket = new AuthenticationTicket(user, new AuthenticationProperties(), Options.AuthenticationScheme);
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
            else
            {
                return Task.FromResult(AuthenticateResult.Fail("No valid user."));
            }
        }

        this.Response.Headers["WWW-Authenticate"]= "Basic realm=\"yourawesomesite.net\"";
        return Task.FromResult(AuthenticateResult.Fail("No credentials."));
    }
}

public class BasicAuthenticationMiddleware : AuthenticationMiddleware<BasicAuthenticationOptions>
{
    public BasicAuthenticationMiddleware(
       RequestDelegate next,
       IOptions<BasicAuthenticationOptions> options,
       ILoggerFactory loggerFactory,
       UrlEncoder encoder)
       : base(next, options, loggerFactory, encoder)
    {
    }

    protected override AuthenticationHandler<BasicAuthenticationOptions> CreateHandler()
    {
        return new BasicAuthenticationHandler();
    }
}

public class BasicAuthenticationOptions : AuthenticationOptions
{
    public BasicAuthenticationOptions()
    {
        AuthenticationScheme = "Basic";
        AutomaticAuthenticate = true;
    }
}

Startup.cs पर पंजीकरण - app.UseMiddleware<BasicAuthenticationMiddleware>();। इस कोड के साथ, आप किसी भी नियंत्रक को standart विशेषता के साथ प्रतिबंधित कर सकते हैं।

[Authorize(ActiveAuthenticationSchemes = "Basic")]
[Route("api/[controller]")]
public class ValuesController : Controller

और AllowAnonymousयदि आप आवेदन स्तर पर फ़िल्टर अधिकृत करते हैं तो विशेषता का उपयोग करें ।


1
मैंने आपके कोड का उपयोग किया है, लेकिन मुझे कोई फर्क नहीं पड़ता कि क्या प्राधिकृत (ActiveAuthenticationSchemes = "बेसिक")] सेट है या नहीं, प्रत्येक कॉल में मिडलवेयर सक्रिय हो जाता है जिसके परिणामस्वरूप प्रत्येक नियंत्रक मान्य नहीं होने पर भी मान्य होता है।
CSharper

मुझे यह उत्तर पसंद है
केटीओवी

1
यहाँ काम करने का उदाहरण: jasonwatmore.com/post/2018/09/08/…
9

मुझे लगता है कि यह उत्तर है कि रास्ता तय करना है, क्योंकि यह आपको समाधान में आगे मानक प्राधिकारी / भत्ता विशेषताओं का उपयोग करने की अनुमति देता है। इसके बाद, परियोजना के चरण में बाद में एक और प्रमाणीकरण योजना का उपयोग करना आसान होना चाहिए जो आवश्यक हो
फ्रेडरिक घीसेल्स 30'19

0

इस सार्वजनिक Github repo https://github.com/boskjoett/BasicAuthWebApi में आप एक ASP.NET Core 2.2 वेब API का एक सरल उदाहरण देख सकते हैं जिसमें बेसिक ऑथेंटिकेशन द्वारा संरक्षित एंडपॉइंट्स हैं।


यदि आप अपने नियंत्रक (SecureValuesController) में प्रमाणीकृत पहचान का उपयोग करना चाहते हैं, तो टिकट बनाना पर्याप्त नहीं है क्योंकि Request.User ऑब्जेक्ट खाली है। क्या हमें अभी भी यह दावा करने की आवश्यकता है कि प्रमाणिकता में वर्तमान संदर्भ के लिए श्रीनिधिलाल को क्या चाहिए? यही कारण है कि हमने इसे पुराने WebApi में किया था ...
pseabury

0

जैसा कि पिछली पोस्टों में कहा गया है, एक तरीका मूल कस्टम प्रमाणीकरण मिडिलवेयर को लागू करना है। मुझे इस ब्लॉग में स्पष्टीकरण के साथ सबसे अच्छा काम करने वाला कोड मिला: कस्टम मिडिलवेयर के साथ बेसिक ऑथ

मैंने एक ही ब्लॉग को संदर्भित किया लेकिन 2 रूपांतरण करने पड़े:

  1. स्टार्टअप फ़ाइल में मिडलवेयर को जोड़ते समय -> फ़ंक्शन को कॉन्फ़िगर करें, ऐप जोड़ने से पहले हमेशा कस्टम मिडलवेयर जोड़ें। यूसिम पीवीसी ()।
  2. उपयोगकर्ता नाम पढ़ते समय, appsettings.json फ़ाइल से पासवर्ड, स्टार्टअप फ़ाइल में केवल पढ़ने के लिए स्थिर संपत्ति जोड़ें। फिर appsettings.json से पढ़ें। अंत में, प्रोजेक्ट में कहीं से भी मान पढ़ें। उदाहरण:

    public class Startup
    {
      public Startup(IConfiguration configuration)
      {
        Configuration = configuration;
      }
    
      public IConfiguration Configuration { get; }
      public static string UserNameFromAppSettings { get; private set; }
      public static string PasswordFromAppSettings { get; private set; }
    
      //set username and password from appsettings.json
      UserNameFromAppSettings = Configuration.GetSection("BasicAuth").GetSection("UserName").Value;
      PasswordFromAppSettings = Configuration.GetSection("BasicAuth").GetSection("Password").Value;
    }
    

0

आप एक का उपयोग कर सकते हैं ActionFilterAttribute

public class BasicAuthAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected NetworkCredential Nc { get; set; }

    public BasicAuthAttribute(string user,string pass)
    {
        this.Nc = new NetworkCredential(user,pass);
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"].ToString();
        if (!String.IsNullOrEmpty(auth))
        {
            var cred = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(auth.Substring(6)))
                .Split(':');
            var user = new {Name = cred[0], Pass = cred[1]};
            if (user.Name == Nc.UserName && user.Pass == Nc.Password) return;
        }

        filterContext.HttpContext.Response.Headers.Add("WWW-Authenticate",
            String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel"));
        filterContext.Result = new UnauthorizedResult();
    }
}

और अपने नियंत्रक में विशेषता जोड़ें

[BasicAuth("USR", "MyPassword")]


-1

कोणीय के साथ ASP.NET कोर 2.0

https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login

प्रमाणीकरण फ़िल्टर के प्रकार का उपयोग करना सुनिश्चित करें

[प्राधिकृत करें (प्रमाणीकरण कार्यशैली = JwtBearerDefaults.AuthenticationScheme]

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.