WebAPI - 如何从令牌中获取用户ID

4

我有一个WebApi应用程序,并在ApplicationOAuthProvider类中将UserID添加到令牌中:

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    {
        foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
        {
            context.AdditionalResponseParameters.Add(property.Key, property.Value);
        }

        context.AdditionalResponseParameters.Add("ID", context.Identity.GetUserId<int>());

        return Task.FromResult<object>(null);
    }

现在我该如何在我的控制器方法中获取这个ID呢?
我尝试了以下方法:
[Authorize]
public class ApiEditorialController : ApiController
{

    public HttpResponseMessage GetEditorialRequests()
    {
        int id = HttpContext.Current.User.Identity.GetUserId<int>();

        var r = Request.CreateResponse(HttpStatusCode.Accepted);
        r.ReasonPhrase = "Cool!";
        return r;
    }

}

但是我在这里遇到了NullReferenceException错误。
int id = HttpContext.Current.User.Identity.GetUserId<int>(); 

字符串....

更新: 查看下面的响应(来自Francis Ducharme),只需覆盖OnAuthorization而不是创建私有构造函数 :)

public class AuthorizeApiFilter : AuthorizeAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        string token = string.Empty;
        AuthenticationTicket ticket;

        token = (actionContext.Request.Headers.Any(x => x.Key == "Authorization")) ? actionContext.Request.Headers.Where(x => x.Key == "Authorization").FirstOrDefault().Value.SingleOrDefault().Replace("Bearer ", "") : "";

        if (token == string.Empty)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Missing 'Authorization' header. Access denied.");
            return;
        }

        //your OAuth startup class may be called something else...
        ticket = Startup.OAuthOptions.AccessTokenFormat.Unprotect(token);

        if (ticket == null)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid token decrypted.");
            return;
        }

        // you could perform some logic on the ticket here...

        // you will be able to retrieve the ticket in all controllers by querying properties and looking for "Ticket"... 
        actionContext.Request.Properties.Add(new KeyValuePair<string, object>("Ticket", ticket));
        base.OnAuthorization(actionContext);
    }
}

谢谢你,Francis Ducharme

非常奇怪,我今天调用了这个项目,它居然正常工作了... - Oleg Sh
2个回答

5
您可以在OAuth启动类的GrantResourceOwnerCredentials方法中将其添加到字典中。
ticket.Properties.Dictionary.Add(KeyValuePair<string, string>("UserID", user.Id.ToString())); //the user object from your authentication logic...

然后实现一个 AuthorizeAttribute,在其中可以检索发送到请求的 Authorize 标头中的令牌,对其进行解密并将其添加到请求属性中,然后可在所有控制器方法中使用该属性。

public class AuthFilter : AuthorizeAttribute
{
    private void AuthorizeRequest(HttpActionContext actionContext)
    {
        string token = string.Empty;
        AuthenticationTicket ticket;

        token = (actionContext.Request.Headers.Any(x => x.Key == "Authorization")) ? actionContext.Request.Headers.Where(x => x.Key == "Authorization").FirstOrDefault().Value.SingleOrDefault().Replace("Bearer ", "") : "";

        if (token == string.Empty)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Missing 'Authorization' header. Access denied.");
            return;
        }

        //your OAuth startup class may be called something else...
        ticket = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(token);

        if (ticket == null)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid token decrypted.");
            return;
        }

        // you could perform some logic on the ticket here...

        // you will be able to retrieve the ticket in all controllers by querying properties and looking for "Ticket"... 
        actionContext.Request.Properties.Add(new KeyValuePair<string, object>("Ticket", ticket));
    }
}

然后在您的Web方法中,Request.Properties将包含Ticket,其中本身有一个带有UserID的字典。

您需要在WebApiConfig.cs中注册AuthorizeAttribute

config.Filters.Add(new AuthFilter());
// I also have this in my Web API config. Not sure if I had to add this manually or the default project had these lines already...
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

我在调用 var ticket = Request.Properties["Ticket"]; 时遇到了一个类型为 'System.Collections.Generic.KeyNotFoundException' 的异常,该异常发生在 mscorlib.dll 中,但未在用户代码中处理。附加信息:字典中不存在给定的键。 - Oleg Sh
非常奇怪,尽管我在WebApiConfig.cs中注册了它,但AuthFilter的代码从未被调用... - Oleg Sh
AuthFilter.AuthorizeRequest从未被调用 - Oleg Sh
@OlegSh 自从我让你在全局注册它以来,请尝试在您的 Web 方法上删除 [Authorize] 属性。 - Francis Ducharme
调试器甚至无法捕获AuthorizeRequest私有构造函数内的断点。该过滤器作为基本授权过滤器运行... - Oleg Sh
显示剩余2条评论

0

您需要拦截响应消息并将该值附加回您的用户。

AdditionalResponseParameters将显示在响应中,但除非您告诉它,否则您的应用程序不会将它们分配给任何内容。

找到您用于将声明值/名称等分配给用户的代码(从OAuth提供程序重定向回您的站点),然后查找响应中的参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接