允许“半匿名”身份验证

时间:2017-11-16 13:35:16

标签: c# authentication asp.net-core asp.net-core-mvc openiddict

我有一个案例,我需要一些经过身份验证的用户可以访问的控制器方法,或者如果请求在URL中包含一种“acccess token”。

例如:

经过身份验证的用户可以拨打以下电话: https://example.com/some/resource

或者,未经过身份验证的用户可以进行相同的调用,但会将某种令牌添加到网址(或作为标题): https://example.com/some/resource?token=123abc

令牌不一定是超级秘密,只有难以猜测的东西。

[AllowSpecialToken]
[HttpGet]
[Route("some/resource")]
public async Task<string> GetSomeResource()
{
    return "some resource";
}

我正在努力的是如何写AllowSpecialTokenAttribute。以及如何在我们现有的身份验证(使用OpenIddict)之前运行它。

这是一个愚蠢的用例吗?我应该找到另一种解决方案吗?

提供一些背景信息:我们有一个SPA来调用我们的API。只需发送链接即可与其他人(非用户)共享SPA的某些页面。该链接将包含令牌。这些页面的内容在安全方面并不重要,但它们不应该完全开放。

2 个答案:

答案 0 :(得分:0)

您需要创建自己的身份验证属性。我过去做过类似的事情,这是我的存根:

public class TokenAuthenticationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        // this will read `token` parameter from your URL
        ValueProviderResult valueProvided = filterContext.Controller.ValueProvider.GetValue("token");
        if (valueProvided == null)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
            return;
        }

        var providedToken = valueProvided.AttemptedValue;

        var storedToken = "12345"; // <-- get your token value from DB or something

        if (storedToken != providedToken)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
            return;
        }
    }
}

然后用属性装饰你的动作:

[TokenAuthentication]
[HttpGet]
[Route("some/resource")]
public async Task<string> GetSomeResource()
{
    return "some resource";
}    

让您的URI看起来像https:\\www.example.com\api\some\resource?token=12345

答案 1 :(得分:0)

您可以尝试下面的内容,看看它是否适合您。 警告:我完全不知道这是否是&#34;正确的&#34;这样做的方式。我只知道这是一种似乎有用的方式。如果您发现问题,请测试并下载。我仍然在我编写的另一个身份验证处理程序上打开question,但没有回复,因此请谨慎使用。如果您打算使用此用例,可能值得联系MS的blowdart(搜索用户)。

中间件类

public class TokenCodeAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public const string DefaultSchemeName = "TokenAuthScheme";

    public TokenCodeAuthHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options, 
        ILoggerFactory logger, 
        UrlEncoder encoder, 
        ISystemClock clock)
        : base(options, logger, encoder, clock)
    {
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        AuthenticateResult result = await this.Context.AuthenticateAsync();
        if (result.Succeeded)
        {
            //User has supplied details
            return AuthenticateResult.Success(result.Ticket);
        }
        else if (Context.Request.Query["token"] == "123abc")   //TODO: Change hard-coded token
        {
            //User has supplied token
            string username = "Test";    //Get/set username here
            var claims = new[]
                {
                    new Claim(ClaimTypes.NameIdentifier, username, ClaimValueTypes.String, Options.ClaimsIssuer),
                    new Claim(ClaimTypes.Name, username, ClaimValueTypes.String, Options.ClaimsIssuer)
                };

            ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));
            AuthenticationTicket ticket = new AuthenticationTicket(principal, Scheme.Name);
            return AuthenticateResult.Success(ticket);
        }
        return AuthenticateResult.Fail("Unauthorized");
    }
}

在启动时配置服务

services.AddAuthentication()
    .AddScheme<AuthenticationSchemeOptions, TokenCodeAuthHandler>(
        TokenCodeAuthHandler.DefaultSchemeName, 
        (o) => { });

属性用法

使用控制器操作如下: 注意 - 我似乎无法覆盖控制器级授权属性。)

[Authorize(AuthenticationSchemes = TokenCodeAuthHandler.DefaultSchemeName)]
[HttpGet]
[Route("some/resource")]
public async Task<string> GetSomeResource()
{
    return "some resource";
}