【问题标题】:Request.GetOwinContext().Get<T> return null in APIControlerRequest.GetOwinContext().Get<T> 在 APIControler 中返回 null
【发布时间】:2017-06-07 13:42:34
【问题描述】:

我无法从 OwinContext 环境中检索我在通过令牌进行身份验证后存储的数据。

这是代码:
[验证客户端身份验证] 在 Thins Code 中,我验证了用户的 ClientID,然后将 ApplicationClient 的数据存储在此行的 OwinContext 中

public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        ...
        ApplicationClient App = new ApplicationClient();
        App.Id = clientId;
        App.ClientSecretHash = clientSecret;
        // Storing Client Data
        context.OwinContext.Set<ApplicationClient>("oauth:client", App);
        context.Validated(clientId);
    }

[GrantResourceOwnerCredentials] 在这里我验证用户凭据并将 Climes 添加到令牌中

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    ...
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    if (Membership.ValidateUser(username, password))
    {          
        identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
        identity.AddClaim(new Claim(ClaimTypes.Name, username));
        context.Validated(identity);
    }
    else
    {
        context.SetError("Login Field", "Error username or password");
    }
}

[ControlerCode] 现在这是我的问题

[Authorize]
public class MyController : ApiController
{
    public IEnumerable<SelectedMenu> GetAllMenus() // Resturants ID
    {
        // client is Null
        ApplicationClient client = HttpContext.Current.GetOwinContext().Get<ApplicationClient>("oauth:client");
    }
}

【问题讨论】:

  • GrantResourceOwnerCredentials 仅在用户请求新令牌时调用。您是否尝试在不同请求之间共享您的ApplicationClient?如果没有某种持久会话,这根本不可能。我强烈建议您避免使用这种方法并使用声明将这些信息存储在令牌中。
  • 另外,你能澄清一下为什么你在你的控制器中需要clientId和clientSecret吗?在 Owin OAuth 管道中验证客户端后,clientSecret 的用途是什么?
  • 嗨 @FedericoDipuma 感谢重播 .. 你说得对,我只需要与我的 API 共享 client_id .. 我将删除密码。但我需要客户端 ID 在运行 API 之前在服务器端检索一些客户端信息。几秒钟前,我刚刚使用 JavaScriptSerializer 将应用程序客户端添加到声明中,然后在 API 控制器上对其进行反序列化,并且它工作正常。但是令牌现在很长:)。那么有没有更好的方法来做到这一点。
  • clientId 有多长?我认为你不需要序列化它,它通常只是一个小字符串。
  • 不只是 ID,该类 ApplicationClient 中大约有 5 个属性

标签: c# asp.net-web-api2 token asp.net-apicontroller


【解决方案1】:

您实际上应该只在您的令牌中添加clientId,这样您就可以在登录过程后随时检索它。

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    // ...
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    if (Membership.ValidateUser(username, password))
    {          
        identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
        identity.AddClaim(new Claim(ClaimTypes.Name, username));
        identity.AddClaim(new Claim("oauth-client", context.ClientId));
        context.Validated(identity);
    }
    else
    {
        context.SetError("Login Field", "Error username or password");
    }
}

您还可以创建一个扩展方法来帮助您检索clientId

public static class PrincipalExtensions
{
    public static string GetClientId(this IPrincipal principal)
    {
        return (principal.Identity as ClaimsIdentity)?
            .Claims
            .FirstOrDefault(c => c.Type == "oauth-client")?
            .Value;
    }    
}

在你的控制器内部:

[Authorize]
public class MyController : ApiController
{
    public IEnumerable<SelectedMenu> GetAllMenus() // Resturants ID
    {
        var clientId = User.GetClientId();
    }
}

关于令牌大小:如果您的clientId 字符串太长,我建议您使用另一个字符串并将任何其他客户端信息(如果需要,包括更长的 id)存储在数据库中。客户端标识符应该是一个易于传输的小而唯一的字符串。

【讨论】:

  • token的长度大概是500个字符左右
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 2019-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多