没有身份的 ASP.NET Core 2.0 承载身份验证

     2023-02-19     30

关键词:

【中文标题】没有身份的 ASP.NET Core 2.0 承载身份验证【英文标题】:ASP.NET Core 2.0 Bearer Auth without Identity 【发布时间】:2018-01-24 16:55:17 【问题描述】:

当我一天前开始在 .NET core 2.0 上实现一个独立的承载身份验证 webapi 时,我以为我有一个非常简单的目标,但我还没有让任何远程工作。这是我正在尝试做的事情的列表:

实现不记名令牌保护的 webapi 从同一项目中的端点发布令牌和刷新令牌 使用 [Authorize] 属性控制对 api 表面的访问 不使用 ASP.Net Identity(我的用户/会员资格要求更轻)

我完全可以在登录中构建身份/声明/主体并将其添加到请求上下文中,但我还没有看到一个关于如何在没有身份的 Core 2.0 webapi 中发布和使用身份验证/刷新令牌的示例.我已经看过没有身份的 1.x MSDN cookie 示例,但这并没有让我理解得足够远,无法满足上述要求。

我觉得这可能是一个常见的场景,它不应该这么难(也许不是,也许只是缺少文档/示例?)。据我所知,IdentityServer4 与 Core 2.0 Auth 不兼容,opendiddict 似乎需要 Identity。我也不想在单独的进程中托管令牌端点,而是在同一个 webapi 实例中。

谁能指出一个具体的例子,或者至少就最佳步骤/选项提供一些指导?

【问题讨论】:

我也很想看看这个示例。 身份与 JWT 机制解耦。阅读this 和this。问候。 【参考方案1】:

进行了编辑以使其与 ASP.NET Core 2.0 兼容。


首先,一些 Nuget 包:

Microsoft.AspNetCore.Authentication.JwtBearer Microsoft.AspNetCore.Identity System.IdentityModel.Tokens.Jwt System.Security.Cryptography.Csp

然后是一些基本的数据传输对象。

// Presumably you will have an equivalent user account class with a user name.
public class User

    public string UserName  get; set; 


public class JsonWebToken

    public string access_token  get; set; 

    public string token_type  get; set;  = "bearer";

    public int expires_in  get; set; 

    public string refresh_token  get; set; 

要使用正确的功能,您需要一个登录/令牌 Web 方法来实际将授权令牌发送给用户。

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

    private ITokenProvider _tokenProvider;

    public TokenController(ITokenProvider tokenProvider) // We'll create this later, don't worry.
    
        _tokenProvider = tokenProvider;
    

    public JsonWebToken Get([FromQuery] string grant_type, [FromQuery] string username, [FromQuery] string password, [FromQuery] string refresh_token)
    
        // Authenticate depending on the grant type.
        User user = grant_type == "refresh_token" ? GetUserByToken(refresh_token) : GetUserByCredentials(username, password);

        if (user == null)
            throw new UnauthorizedAccessException("No!");

        int ageInMinutes = 20;  // However long you want...

        DateTime expiry = DateTime.UtcNow.AddMinutes(ageInMinutes);

        var token = new JsonWebToken 
            access_token = _tokenProvider.CreateToken(user, expiry),
            expires_in   = ageInMinutes * 60
        ;

        if (grant_type != "refresh_token")
            token.refresh_token = GenerateRefreshToken(user);

        return token;
    

    private User GetUserByToken(string refreshToken)
    
        // TODO: Check token against your database.
        if (refreshToken == "test")
            return new User  UserName = "test" ;

        return null;
    

    private User GetUserByCredentials(string username, string password)
    
        // TODO: Check username/password against your database.
        if (username == password)
            return new User  UserName = username ;

        return null;
    

    private string GenerateRefreshToken(User user)
    
        // TODO: Create and persist a refresh token.
        return "test";
    

您可能注意到令牌创建仍然只是由一些虚构的 ITokenProvider 传递的“魔法”。定义令牌提供者接口。

public interface ITokenProvider

    string CreateToken(User user, DateTime expiry);

    // TokenValidationParameters is from Microsoft.IdentityModel.Tokens
    TokenValidationParameters GetValidationParameters();

我在 JWT 上使用 RSA 安全密钥实现了令牌创建。所以...

public class RsaJwtTokenProvider : ITokenProvider

    private RsaSecurityKey _key;
    private string _algorithm;
    private string _issuer;
    private string _audience;

    public RsaJwtTokenProvider(string issuer, string audience, string keyName)
    
        var parameters = new CspParameters  KeyContainerName = keyName ;
        var provider = new RSACryptoServiceProvider(2048, parameters);

        _key = new RsaSecurityKey(provider);

        _algorithm = SecurityAlgorithms.RsaSha256Signature;
        _issuer = issuer;
        _audience = audience;
    

    public string CreateToken(User user, DateTime expiry)
    
        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

        ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user.UserName, "jwt"));

        // TODO: Add whatever claims the user may have...

        SecurityToken token = tokenHandler.CreateJwtSecurityToken(new SecurityTokenDescriptor
        
            Audience = _audience,
            Issuer = _issuer,
            SigningCredentials = new SigningCredentials(_key, _algorithm),
            Expires = expiry.ToUniversalTime(),
            Subject = identity
        );

        return tokenHandler.WriteToken(token);
    

    public TokenValidationParameters GetValidationParameters()
    
        return new TokenValidationParameters
        
            IssuerSigningKey = _key,
            ValidAudience = _audience,
            ValidIssuer = _issuer,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.FromSeconds(0) // Identity and resource servers are the same.
        ;
    

所以您现在正在生成令牌。是时候实际验证它们并将其连接起来了。转到您的 Startup.cs。

ConfigureServices()

var tokenProvider = new RsaJwtTokenProvider("issuer", "audience", "mykeyname");
services.AddSingleton<ITokenProvider>(tokenProvider);

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => 
        options.RequireHttpsMetadata = false;
        options.TokenValidationParameters = tokenProvider.GetValidationParameters();
    );

// This is for the [Authorize] attributes.
services.AddAuthorization(auth => 
    auth.DefaultPolicy = new AuthorizationPolicyBuilder()
        .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
        .RequireAuthenticatedUser()
        .Build();
);

然后Configure()

public void Configure(IApplicationBuilder app)

    app.UseAuthentication();

    // Whatever else you're putting in here...

    app.UseMvc();

这应该就是你所需要的。希望我没有错过任何东西。

幸福的结果是……

[Authorize] // Yay!
[Route("api/values")]
public class ValuesController : Controller

    // ...

【讨论】:

我什至没有真正想过用新的 Core2 身份验证堆栈等的所有讨论来推出自己的产品 - 我认为这将是现成的。在任何情况下,您的解决方案中唯一缺少的是刷新令牌,但鉴于上述情况,这是微不足道的。一个问题 - 这些安全令牌是不透明的还是透明的? (即,当出现令牌时,身份验证堆栈是否取消保护并将身份附加到 webapi 上下文,或者这是一个额外的步骤?)谢谢米奇! 它解密令牌并为您设置上下文身份。在您的控制器中,User.Identity.Name 将是传递给 JWT 的用户名。 是的,我还没来得及刷新令牌——不过它的运行与 JWT 生成代码完全不同。通过一些随机哈希生成令牌,存储它,并在刷新调用期间检查它。这段代码是我在 .NET Core beta 阶段必须重新编写的快速 API。如果有人对新功能有更简单的实现,那就太好了。 在 Configure() 方法中,我收到一个错误,表明 UseJwtBearerAuthentication() 已过时,它引用了一些令人费解的文章(读起来更像是仍在实施过程中的 MS 编码员之间的内部讨论这)。我不想使用任何类型的身份服务器。有人请告诉我完成这项工作的唯一方法不是回滚到 asp.net core 1.1。 MS:你为什么一直这样对我们? 请注意,在 Mac OS X 上使用 .NET Core 2 时,当涉及“var provider = new RSACryptoServiceProvider(2048, parameters);”时,您将收到 System.PlatformNotSupportedException。 *** 上有关于这个问题的单独线程 ....【参考方案2】:

在@Mitch 回答之后:身份验证堆栈发生了很大变化,迁移到 .NET Core 2.0。下面的答案只是使用新的实现。

using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;

namespace JwtWithoutIdentity

    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.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(cfg =>
                
                    cfg.RequireHttpsMetadata = false;
                    cfg.SaveToken = true;

                    cfg.TokenValidationParameters = new TokenValidationParameters()
                    
                        ValidIssuer = "me",
                        ValidAudience = "you",
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("rlyaKithdrYVl6Z80ODU350md")) //Secret
                    ;

                );

            services.AddMvc();
        

        // 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();
        
    

令牌控制器

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using JwtWithoutIdentity.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace JwtWithoutIdentity.Controllers

    public class TokenController : Controller
    

        [AllowAnonymous]
        [Route("api/token")]
        [HttpPost]
        public async Task<IActionResult> Token(LoginViewModel model)
        

            if (!ModelState.IsValid) return BadRequest("Token failed to generate");

            var user = (model.Password == "password" && model.Username == "username");

            if (!user) return Unauthorized();

            //Add Claims
            var claims = new[]
            
                new Claim(JwtRegisteredClaimNames.UniqueName, "data"),
                new Claim(JwtRegisteredClaimNames.Sub, "data"),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            ;

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("rlyaKithdrYVl6Z80ODU350md")); //Secret
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken("me",
                "you",
                claims,
                expires: DateTime.Now.AddMinutes(30),
                signingCredentials: creds);

            return Ok(new JsonWebToken()
            
                access_token = new JwtSecurityTokenHandler().WriteToken(token),
                expires_in = 600000,
                token_type = "bearer"
            );
        
    

值控制器

using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace JwtWithoutIdentity.Controllers

    [Route("api/[controller]")]
    public class ValuesController : Controller
    
        // GET api/values
        [Authorize]
        [HttpGet]
        public IEnumerable<string> Get()
        
            var name = User.Identity.Name;
            var claims = User.Claims;

            return new string[]  "value1", "value2" ;
        
    

希望这会有所帮助!

【讨论】:

感谢您发布此信息。正在寻找类似的东西。我只是想知道如果您不使用User : Identity,为什么您仍然拥有声明和身份。

ASP.NET Core 2.0 为同一端点结合了 Cookie 和承载授权

】ASP.NETCore2.0为同一端点结合了Cookie和承载授权【英文标题】:ASP.NETCore2.0combiningCookiesandBearerAuthorizationforthesameendpoint【发布时间】:2018-04-0621:17:53【问题描述】:我在VS17中使用“Web应用程序(模型-视图-控制器)”模板和“.NetFr... 查看详情

ASP.NET Core 2.0 身份验证中间件

】ASP.NETCore2.0身份验证中间件【英文标题】:ASP.NETCore2.0authenticationmiddleware【发布时间】:2018-01-3000:26:44【问题描述】:Core1.1遵循@blowdart的建议并实现了自定义中间件:https://***.com/a/31465227/29821它是这样工作的:中间件已运行。... 查看详情

如何在 ASP.NET Core 2.0 中设置多个身份验证方案?

】如何在ASP.NETCore2.0中设置多个身份验证方案?【英文标题】:HowdoIsetupmultipleauthschemesinASP.NETCore2.0?【发布时间】:2018-01-2312:34:16【问题描述】:我正在尝试将我的身份验证内容迁移到Core2.0,但在使用我自己的身份验证方案时遇... 查看详情

没有 ASP.NET 身份的 .NET Core 外部身份验证

】没有ASP.NET身份的.NETCore外部身份验证【英文标题】:.NETCoreExternalAuthenticationwithoutASP.NETIdentity【发布时间】:2018-06-1516:09:59【问题描述】:我使用自己的JWT令牌身份验证,而不是默认模板免费提供的asp.net身份。我到处寻找一些... 查看详情

如何从 ASP.NET Core 2.0 中的自定义中间件请求身份验证

】如何从ASP.NETCore2.0中的自定义中间件请求身份验证【英文标题】:HowtorequestauthenticationfromcustommiddlewareinASP.NETCore2.0【发布时间】:2018-10-2118:41:09【问题描述】:我有两个自定义ASP.NETCore中间件:一个用于身份验证(注册自己的身... 查看详情

如何在 ASP.NET Core 2.0 中根据路由配置服务身份验证

】如何在ASP.NETCore2.0中根据路由配置服务身份验证【英文标题】:HowtoConfigureServicesAuthenticationbasedonroutesinASP.NETCore2.0【发布时间】:2018-03-0922:06:40【问题描述】:在ASP.NETCore1.x中,我可以在Configure中使用身份验证方法,但现在在ASP... 查看详情

asp.net core 2.0 授权在身份验证(JWT)之前触发

】asp.netcore2.0授权在身份验证(JWT)之前触发【英文标题】:asp.netcore2.0Authorizationisfiringbeforeauthentication(JWT)【发布时间】:2018-08-2917:53:24【问题描述】:我正在尝试在我的asp.netcore2.0应用程序中实施自定义授权策略。在我的自定... 查看详情

在 ASP.NET Core 2.0 中使用带有身份模型的 Azure Active Directory OAuth

】在ASP.NETCore2.0中使用带有身份模型的AzureActiveDirectoryOAuth【英文标题】:UsingAzureActiveDirectoryOAuthwithIdentityModelinASP.NETCore2.0【发布时间】:2018-04-2115:12:24【问题描述】:问题陈述我们正在开发一个新的企业级应用程序,并希望利用... 查看详情

ASP.net Core 2.0 JWT 令牌刷新

...将到期时间设置为30分钟,与身份Cookie到期时间相同。我没有遇到任何有 查看详情

从 ASP.NET Core 1.1 MVC 迁移到 2.0 后,自定义 cookie 身份验证不起作用

】从ASP.NETCore1.1MVC迁移到2.0后,自定义cookie身份验证不起作用【英文标题】:CustomcookieauthenticationnotworkingaftermigrationfromASP.NETCore1.1MVCto2.0【发布时间】:2018-06-1221:38:23【问题描述】:我已将ASP.NETCore1.1MVC项目迁移到ASP.NETCore2.0,现... 查看详情

在 ASP.NET Core 中使用多个身份验证方案

】在ASP.NETCore中使用多个身份验证方案【英文标题】:UsingmultipleauthenticationschemesinASP.NETCore【发布时间】:2017-10-0316:31:39【问题描述】:我有使用ASP.NETCore开发的WebAPI,我需要能够为同一服务使用基本和不记名身份验证方案。由于... 查看详情

同一站点中的 asp net core 2.0 JWT 和 Openid Connect 身份验证

】同一站点中的aspnetcore2.0JWT和OpenidConnect身份验证【英文标题】:aspnetcore2.0JWTandOpenIDConnectAuthenticationinsamesite【发布时间】:2018-07-0316:43:48【问题描述】:我们有一个aspnetcore2.0网站。该网站的大部分内容是WebAPI,有2个UI组件:swag... 查看详情

同时对 Asp.Net core 2.0 MVC 应用程序 (cookie) 和 REST API (JWT) 进行身份验证

】同时对Asp.Netcore2.0MVC应用程序(cookie)和RESTAPI(JWT)进行身份验证【英文标题】:AuthenticatingtoAsp.Netcore2.0MVCapplication(cookie)andRESTAPI(JWT)simultaneously【发布时间】:2018-05-0608:28:21【问题描述】:我正在使用带有React.js模板选项的VS2017Asp.Ne... 查看详情

ASP.Net Core - API 身份验证错误没有重定向

】ASP.NetCore-API身份验证错误没有重定向【英文标题】:ASP.NetCore-noredirectonAPIautherror【发布时间】:2017-05-2321:58:21【问题描述】:在我的ASP.NETCore项目中,我得到了一些带有jwt授权的API控制器,如下所示:[Route("api/v1/[controller]")]publ... 查看详情

如何在 ASP.NET Core 2.0 Web api 中添加来自 IdentityServer4 和 Auth0 的 Jwt 身份验证?

...如何在ASP.NETCore2.0Webapi中添加来自IdentityServer4和Auth0的Jwt身份验证?【英文标题】:HowdoIaddJwtauthenticationfromIdentityServer4andAuth0inanASP.NETCore2.0webapi?【发布时间】:2018-05-1605:24:51【问题描述】:我们需要使用来自IdentityServer4的JWT令牌... 查看详情

Asp.Net Core 2 验证承载令牌

】Asp.NetCore2验证承载令牌【英文标题】:Asp.NetCore2Validatingbearertoken【发布时间】:2019-11-1901:52:34【问题描述】:我正在努力寻找一种准确的方法来验证我的OAuthbearer令牌,该令牌是在将请求发送到正在处理的API时传递的,该API是... 查看详情

asp.net core + angular2 JWT 承载

】asp.netcore+angular2JWT承载【英文标题】:asp.netcore+angular2JWTbearer【发布时间】:2017-03-0723:30:53【问题描述】:我正在寻找如何使用angular2在asp.net-core1.0中使用JWT承载实现授权。请问你们要样品之类的吗?【问题讨论】:github.com/open... 查看详情

在 HTTPS 上使用 Windows 身份验证首次调用 ASP.NET Core 2.0 Web API 在 Chrome 中总是失败

】在HTTPS上使用Windows身份验证首次调用ASP.NETCore2.0WebAPI在Chrome中总是失败【英文标题】:FirstcalltoASP.NETCore2.0WebAPIwithWindowsauthenticationonHTTPSalwaysfailsinChrome【发布时间】:2017-10-0409:39:18【问题描述】:我正在使用带有Windows身份验证... 查看详情