首页 文章

ASP.NET Core Web API身份验证

提问于
浏览
50

我正在努力解决如何在我的Web服务中设置身份验证的问题 . 该服务是使用ASP.NET Core web api构建的 .

我的所有客户端(WPF应用程序)都应使用相同的凭据来调用Web服务操作 .

经过一些研究,我想出了基本的身份验证 - 在HTTP请求的标头中发送用户名和密码 . 但经过几个小时的研究,在我看来,基本身份验证不是ASP.NET Core的方法 .

我发现的大多数资源都是使用OAuth或其他一些中间件实现身份验证 . 但是对于我的场景,以及使用ASP.NET Core的Identity部分,这似乎过大了 .

那么实现我的目标的正确方法是什么 - 在ASP.NET Core Web服务中使用用户名和密码进行简单的身份验证?

提前致谢!

6 回答

  • 13

    您可以实现处理基本身份验证的中间件 .

    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核心的beta版本中编写的 . 希望能帮助到你 .

  • 3

    现在,在我指出正确的方向后,这是我的完整解决方案:

    这是在每个传入请求上执行的中间件类,并检查请求是否具有正确的凭据 . 如果没有凭据或者它们是错误的,则服务立即响应401 Unauthorized错误 .

    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;
            }
        }
    }
    

    需要在服务Startup类的Configure方法中调用中间件扩展

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
    
        app.UseMiddleware<AuthenticationMiddleware>();
    
        app.UseMvc();
    }
    

    就这样! :)

    可以在此处找到.Net Core中的中间件和身份验证的非常好的资源:https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/

  • 0

    要仅将其用于特定控制器,请使用以下命令:

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

    我想你可以和JWT(Json Web Tokens)一起去 .

    首先,您需要安装包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("H38DLSIEKD8EKDOS")),
                                             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("H38DLSIEKD8EKDOS")),
                    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/

  • 62

    我已经实现 BasicAuthenticationHandler 进行基本身份验证,因此您可以将它与标准属性 AuthorizeAllowAnonymous 一起使用 .

    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(':');
    
                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>(); . 使用此代码,您可以使用标准属性Autorize限制任何控制器:

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

    如果在应用程序级别应用授权筛选器,请使用属性 AllowAnonymous .

  • 7

    ASP.NET Core 2.0 with Angular

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

    确保使用验证过滤器类型

    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

相关问题