首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >作为get param的aspnet核心jwt令牌

作为get param的aspnet核心jwt令牌
EN

Stack Overflow用户
提问于 2017-11-28 13:27:25
回答 2查看 5.5K关注 0票数 15

我正在工作一个aspnet核心2webAPI项目,它的主要消费者是一个vue web应用程序。

Api使用jwt令牌作为身份验证方法,一切都很好。

现在,我已经安装了所有代码来管理数据库中的图像存储和检索,但我在从db中获取图像方面遇到了问题。

所有路由(登录除外)都是身份验证后的,因此为了检索图像,我在请求头(通常)中有传递令牌。

这使我无法使用图像源标记来实际显示图像,如

代码语言:javascript
运行
复制
<img src="/api/images/27" />

相反,我必须编写一些javascript代码来请求图像并将内容放在图像标记中,如下所示

代码语言:javascript
运行
复制
// extracted from vue code (not my code, i'm the backend guy)
getImage() {
    this.$http.get('api/images/27', {headers: {'Authorization': 'Bearer ' + this.token},responseType: 'blob'})
    .then(response => {
        return response.blob()
    }).then(blob => { 
        this.photoUrl = URL.createObjectURL(blob)
    })
}

这是可行的,但不知何故,这是一个不必要的复杂。

我在AspNet核心身份中看到

或者,您可以从其他地方获得令牌,例如不同的头,甚至cookie。在这种情况下,处理程序将使用提供的令牌进行所有进一步的处理。

(摘自Andre博客中的文章)您还可以看到检查aspnet核心安全代码,其中写道

给应用程序从不同位置查找、调整或拒绝令牌的机会

但是,我找不到关于如何使用此功能并传递自定义令牌的任何示例。

因此,我的问题是:是否有人知道如何将自定义令牌(可能从get参数中读取)传递给身份提供者(甚至可能仅针对某些已定义的路由)?

感谢serpent5给出的正确答案。

如果有人感兴趣,从url param读取令牌并将其传递给验证的完整代码如下

代码语言:javascript
运行
复制
service.AddAuthentication(...)
    .AddJwtBearer(options =>
        // ...
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = ctx =>
            {
                // replace "token" with whatever your param name is
                if (ctx.Request.Method.Equals("GET") && ctx.Request.Query.ContainsKey("token"))
                    ctx.Token = ctx.Request.Query["token"];
                return Task.CompletedTask;
            }
        };
    });
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-11-28 14:00:26

这可以使用连接到提供给JwtBearerEventsJwtBearerOptions实例的AddJwtBearer来处理。具体来说,可以实现一个OnMessageReceived事件来提供令牌本身。下面是一个例子:

代码语言:javascript
运行
复制
services.AddAuthentication(...)
    .AddJwtBearer(jwtBearerOptions =>
    {
        // ...

        jwtBearerOptions.Events = new JwtBearerEvents
        {
            OnMessageReceived = ctx =>
            {
                // Access ctx.Request here for the query-string, route, etc.
                ctx.Token = "";
                return Task.CompletedTask;
            }
        };
    })

您可以看到这是如何在源代码中使用的

代码语言:javascript
运行
复制
// event can set the token
await Events.MessageReceived(messageReceivedContext);

// ...

// If application retrieved token from somewhere else, use that.
token = messageReceivedContext.Token;
票数 12
EN

Stack Overflow用户

发布于 2017-11-28 13:50:53

您的应用程序可以提供此功能,例如,使用正确的凭据登录。(前端->登录正确的->后端发送回JWT令牌。)

然后,您可以将后端给您的令牌存储在cookie/localstorage中。

每次将请求发送回API时,只需从cookie/localstorage检索令牌并将其添加到请求头。

我将向您展示如何添加处理令牌生成和验证的中间件的示例。

appsettings.conf

代码语言:javascript
运行
复制
{
  "Secret": {
    "Key": "abcdefghijklmnop123456789"
  }
}

密钥用于生成唯一的JWT令牌,应该分别存储在机器上,例如,这就是目的。

TokenProviderOptions.cs

代码语言:javascript
运行
复制
public class TokenProviderOptions
{
    public string Path { get; set; } = "/token";
    public string Issuer { get; set; }
    public string Audience { get; set; }
    public TimeSpan Expiration { get; set; } = TimeSpan.FromHours(1);
    public SigningCredentials SigningCredentials { get; set; }
}

将为我们提供令牌生成的基本信息的类。可以将“路径”更改为要检索令牌的任何路径。

TokenProviderMiddleware.cs

代码语言:javascript
运行
复制
public class TokenProviderMiddleware
{
    private readonly RequestDelegate _next;
    private readonly TokenProviderOptions _options;
    private readonly IAccountService _accountService;

    public TokenProviderMiddleware(RequestDelegate next, IOptions<TokenProviderOptions> options, IAccountService accounteService)
    {
        _next = next;
        _options = options.Value;
        _accountService = accounteService;
    }

    public Task Invoke(HttpContext context)
    {
        //Check path request
        if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal)) return _next(context);

        //METHOD: POST && Content-Type : x-www-form-urlencode
        if (context.Request.Method.Equals("POST") && context.Request.HasFormContentType)
            return GenerateToken(context);


        context.Response.StatusCode = 400;
        return context.Response.WriteAsync("Bad Request");
    }

    private async Task GenerateToken(HttpContext context)
    {
        var username = context.Request.Form["username"];
        var password = context.Request.Form["password"];

        var identity = await GetIdentity(username, password);

        if (identity == null)
        {
            context.Response.StatusCode = 400;
            await context.Response.WriteAsync("Invalid username or password");
            return;
        }

        var now = DateTime.UtcNow;

        var claims = new Claim[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, username),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, now.Second.ToString(), ClaimValueTypes.Integer64)
        };

        var jwt = new JwtSecurityToken(
            issuer: _options.Issuer,
            audience: _options.Audience,
            claims: claims,
            notBefore: now,
            expires: now.Add(_options.Expiration),
            signingCredentials: _options.SigningCredentials);

        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

        var response = new
        {
            access_token = encodedJwt,
            expires_in = (int)_options.Expiration.TotalSeconds,
            username = username
        };

        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(JsonConvert.SerializeObject(response,
            new JsonSerializerSettings { Formatting = Formatting.Indented }));
    }

    private Task<ClaimsIdentity> GetIdentity(string username, string password)
    {
        //THIS STEP COULD BE DIFFERENT, I HAVE AN ACCOUNTSERVICE THAT QUERIES MY DB TO CHECK THE USER CREDENTIALS
        var auth = _accountService.Login(username, password).Result;
        return auth
            ? Task.FromResult(new ClaimsIdentity(new GenericIdentity(username, "Token"), new Claim[] { }))
            : Task.FromResult<ClaimsIdentity>(null);
    }
}

这是中间件部分。您必须将标题类型为application/x-www-form-urlencoded和2个字段usernamepassword的POST请求发送到您在TokenProviderOptions中定义的Path

如果检查通过,您将得到一个jwt令牌。

最后是Startup.cs

代码语言:javascript
运行
复制
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; set; }

    public void ConfigureServices(IServiceCollection services)
    {
        //Mvc
        services.AddMvc();

        //...

        //Authentication
        services.AddAuthentication()
            .AddJwtBearer(jwt =>
            {
                var signingKey =
                    new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("Secret:Key").Value));

                jwt.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = signingKey,

                    ValidateIssuer = true,
                    ValidIssuer = "2CIssuer",

                    ValidateAudience = true,
                    ValidAudience = "2CAudience",

                    ValidateLifetime = true,

                    ClockSkew = TimeSpan.Zero
                };
            });

        //Authorization
        services.AddAuthorization(auth =>
        {
            auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build());
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        //...

        //Authentication
        var signingKey =
            new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("Secret:Key").Value));

        var options = new TokenProviderOptions
        {
            Audience = "2CAudience",
            Issuer = "2CIssuer",
            SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
        };

        app.UseAuthentication();

        //JWT
        app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));

        //Mvc
        app.UseMvc();
    }
}

我遗漏了多余的代码。这增加了您的自定义中间件en将应用程序配置为使用JWT令牌。

您所要做的就是更改所提到的自定义参数,用‘token’签上您的请求: tokenValue,您就好了!

我在这里有一个工作的后端模板:模板,可以对所有内容进行双重检查。

希望能帮上忙!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47532751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档