【问题标题】:Owin Bearer Token Not Working for WebApiOwin Bearer 令牌不适用于 WebApi
【发布时间】:2014-10-18 11:04:59
【问题描述】:

我已经阅读了大量关于此的文档,我的谷歌搜索显示我已经访问了第一页上的所有链接

问题 令牌生成工作正常。我使用自定义提供程序对其进行了配置:

    public void ConfigureOAuth(IAppBuilder app)
    {
        var usermanager = NinjectContainer.Resolve<UserManager>(); 
        app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new AppOAuthProvider(usermanager)
        });
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }

但是,当我调用受保护的 URL 并传递不记名令牌时,我总是得到:

如何诊断或解决问题。如果可能,我如何自己进行令牌验证

更新 这是我的 AppOAuthProvider。两种方法都在我尝试铸造令牌时调用,但在我尝试访问受保护资源时不会调用

public class AppOAuthProvider : OAuthAuthorizationServerProvider
{
    private UserManager _user;
    public AppOAuthProvider(UserManager user)
    {
        _user = user;
    }
    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

    public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        //Get User Information
        var getUser = _user.FindUser(context.UserName);
        if (getUser.Status == StatusCode.Failed)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return Task.FromResult<object>(null);
        }

        var user = getUser.Result;

        //Get Roles for User
        var getRoles = _user.GetRoles(user.UserID);
        if (getRoles.Status == StatusCode.Failed)
        {
            context.SetError("invalid_grant", "Could not determine Roles for the Specified User");
        }

        var roles = getRoles.Result;

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("UserID", user.UserID.ToString()));
        identity.AddClaim(new Claim("UserName", user.UserName));

        foreach (var role in roles)
        {
            identity.AddClaim(new Claim(ClaimTypes.Role, role));
        }

        context.Validated(identity);

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

更新 2: 这是我的帐户控制人

[RoutePrefix("api/auth/account")]
public class AccountController : ApiController
{
    private UserManager _user;
    public AccountController(UserManager user)
    {
        _user = user;
    }

    [Authorize]
    [HttpGet]
    [Route("secret")]
    public IHttpActionResult Secret()
    {
        return Ok("Yay! Achievement Unlocked");
    }
}

更新 3: 这是我的 Startup.cs

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseNinjectMiddleware(NinjectContainer.CreateKernel);
        app.UseNinjectWebApi(GlobalConfiguration.Configuration);
        GlobalConfiguration.Configure(WebApiConfig.Register);
        ConfigureOAuth(app);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(GlobalConfiguration.Configuration);
        app.UseWelcomePage();
    }
}

【问题讨论】:

标签: c# asp.net-web-api oauth owin


【解决方案1】:

在您的提供商中,您必须:

public override ValidateClientAuthentication(OAuthClientAuthenticationContext context)
{
    //test context.ClientId
    //if you don't care about client id just validate the context
    context.Validated();
}

这样做的原因是,如果您不覆盖 ValidateClientAuthentication 并验证上下文,则会假定它被拒绝,并且您将始终收到该错误。

【讨论】:

  • 这就是我所做的,但我仍然得到“未授权”。我已更新问题以显示我的 AppOAuthProvider 类
  • @Ody 你能在你的 GrantResourceOwnerCredentials 方法中添加一个断点并确保它被命中吗?
  • 是的,当我尝试创建令牌时,这两种方法都会被调用,并且工作正常。但是,当我尝试访问受保护的资源时,两者都没有被调用。
  • @Ody 你能告诉我们你的行动方法吗?你能确定它是用Authorize attribute from System.Web.Http注释的吗?
  • @Ody 这些方法(GrantResourceOwnerCredentials 和 ValidateClientAuthentication)只能在获取令牌时调用,当您使用令牌时,它是使用的 OAuthBearerAuthentication 中间件
【解决方案2】:
    HttpConfiguration config = new HttpConfiguration();
app.UseNinjectMiddleware(NinjectContainer.CreateKernel);
app.UseNinjectWebApi(GlobalConfiguration.Configuration);
ConfigureOAuth(app);
WebApiConfig.Register(config);
//GlobalConfiguration.Configure(WebApiConfig.Register);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// app.UseWebApi(GlobalConfiguration.Configuration);
app.UseWebApi(config);
app.UseWelcomePage();

我在 github 上使用你的示例应用程序进行了尝试,它成功了

【讨论】:

  • 请注意,此答案中的排序在我的应用程序中至关重要。我使用的是 SimpleInjector,而不是 Ninject,但我根本不需要在 Startup 类中使用 GlobalConfiguration.Configuration ......只需传递创建的配置就足够了。在上面的示例中,它仍然在第 3 行中使用。
  • @sannee 原来这是问题所在。另外,为了让 DI 工作,我必须在 app.UseWebApi(config) 之前移动 app.UseNinjectWebApi
【解决方案3】:

在调用 IAppBuilder 上的 UseWebApi 之前,您必须配置 OAuth 授权服务器和 OAuth 持有者身份验证。以下来自我的程序。

    public void Configuration(IAppBuilder app)
    {
        app.UseFileServer(new FileServerOptions()
        {
            RequestPath = PathString.Empty,
            FileSystem = new PhysicalFileSystem(@".\files")
        });

        // set the default page
        app.UseWelcomePage(@"/index.html");

        ConfigureAuth(app);

        HttpConfiguration config = new HttpConfiguration();

        config.Routes.MapHttpRoute
        (
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional } 
        );

        config.Formatters.Clear();
        config.Formatters.Add(new JsonMediaTypeFormatter());
        config.Formatters.JsonFormatter.SerializerSettings =
        new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };

        app.UseCors(CorsOptions.AllowAll);
        app.UseWebApi(config);


    }

    public void ConfigureAuth(IAppBuilder app)
    {
        OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new YourApplicationOAuthProvider()
        };

        app.UseOAuthAuthorizationServer(oAuthServerOptions);
        app.UseOAuthBearerAuthentication
        (
            new OAuthBearerAuthenticationOptions 
            {
                Provider = new OAuthBearerAuthenticationProvider()
            }
        );
    }

【讨论】:

  • 这对我帮助很大!谢谢!
  • 很好的答案。我现在知道为什么它不起作用了。事后看来,这一切都说得通。我现在想知道我在想什么。UseNinjectWebApi 注册 WebAPI。我把它放在ConfigureAuth 上面,因为我的身份验证块中需要 Ninject。 @ojorma 解决方案有效,因为他重新注册了 WebAPI。感谢您的回复
  • 谢谢,我遇到了同样的问题,因为我在调用 UseWebApi 之后调用了 ConfigureAuth 例程。在配置例程中的所有其他内容解决问题之前,移动 ConfigureAuth 调用以运行。
猜你喜欢
  • 2014-03-22
  • 2018-08-22
  • 2020-04-18
  • 2014-10-05
  • 2015-07-02
  • 2020-10-15
  • 1970-01-01
  • 2013-11-25
  • 2018-11-26
相关资源
最近更新 更多