C# Owin承载令牌身份验证+;授权控制员

C# Owin承载令牌身份验证+;授权控制员,c#,authentication,token,owin,C#,Authentication,Token,Owin,我正在尝试使用承载令牌和owin进行身份验证 我可以使用授权类型password和覆盖AuthorizationServerProvider.cs中的GrantResourceOwnerCredentials来颁发令牌罚款 但我无法访问带有Authorize属性的控制器方法 这是我的密码: Startup.cs public class Startup { public static OAuthAuthorizationServerOptions OAuthOptions { get;

我正在尝试使用承载令牌和owin进行身份验证

我可以使用授权类型
password
和覆盖AuthorizationServerProvider.cs中的
GrantResourceOwnerCredentials
来颁发令牌罚款

但我无法访问带有
Authorize
属性的控制器方法

这是我的密码:

Startup.cs

public class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    // normal
    public Startup() : this(false) { }

    // testing
    public Startup(bool isDev)
    {
        // add settings
        Settings.Configure(isDev);

        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/Token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new AuthorizationServerProvider()
        };
    }

    public void Configuration(IAppBuilder app)
    {
        // Configure the db context, user manager and role manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
        app.CreatePerOwinContext<LoanManager>(BaseManager.Create);

        var config = new HttpConfiguration();
        WebApiConfig.Register(config);
        app.UseWebApi(config);

        // token generation
        app.UseOAuthAuthorizationServer(OAuthOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
        {
            AuthenticationType = "Bearer",
            AuthenticationMode = AuthenticationMode.Active
        });
    }
}
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

        IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }

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

        context.Validated(identity);
    }
}
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        // enable CORS for all hosts, headers and methods
        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);

        config.Routes.MapHttpRoute(
            name: "optional params",
            routeTemplate: "api/{controller}"
        );

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

        // stop cookie auth
        config.SuppressDefaultHostAuthentication();
        // add token bearer auth
        config.Filters.Add(new MyAuthenticationFilter());
        //config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthOptions.AuthenticationType));

        config.Filters.Add(new ValidateModelAttribute());

        if (Settings.IsDev == false)
        {
            config.Filters.Add(new AuthorizeAttribute());
        }

        // make properties on model camelCased
        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
    }
public partial class Startup
{
    public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
    ...

    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per    request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        ...
    }
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    /*This will depend totally on how you will get access to the identity provider and get your token, this is just a sample of how it would be done*/
    /*Get Access Token Start*/
    HttpClient httpClient = new HttpClient();
    httpClient.BaseAddress = new Uri("https://youridentityproviderbaseurl");
    var postData = new List<KeyValuePair<string, string>>();
    postData.Add(new KeyValuePair<string, string>("UserName", model.Email));
    postData.Add(new KeyValuePair<string, string>("Password", model.Password));
    HttpContent content = new FormUrlEncodedContent(postData);


    HttpResponseMessage response = await httpClient.PostAsync("yourloginapi", content);
    response.EnsureSuccessStatusCode();
    string AccessToken = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
    /*Get Access Token End*/

    If(!string.IsNullOrEmpty(AccessToken))
    {
            var ticket = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(AccessToken);
            var id = new ClaimsIdentity(ticket.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, id);

            return RedirectToLocal(returnUrl);

   }

   ModelState.AddModelError("Error", "Invalid Authentication");
   return View();
}
public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

        …
    }
}
如果我在MyAuthenticationFilter.cs中调试
authenticateSync
,我会在请求中看到标题:

Authorization: Bearer AQAAANCMnd8BFdERjHoAwE_Cl...
但是身份声明是空的,
context.Principal.Identity.IsAuthenticated
为false


有什么想法吗?

我不确定这是否有帮助,但在使用依赖项注入时,我遇到了一个问题,IsAuthenticated返回false(请参见问题),它看起来是错误的,因为在注入点,它没有被Owin管道设置


我通过校长的懒惰克服了它。无论哪种方式,我都编写了一个非常基本的应用程序(在上面链接到)来演示这个问题,但它可能会对您有所帮助,因为它显示了在属性中设置的主体以及承载身份验证的使用。

我一直在寻找相同的解决方案,我花了一周左右的时间才离开它。今天我又开始搜索了,我找到了你们的问题,我希望能找到答案

因此,我花了一整天的时间,除了尝试所有可能的解决方案,相互合并建议,我找到了一些解决方案,但它们是长期的变通办法,让长话短说,这就是我发现的

首先,如果需要使用自定义的第三方身份提供程序令牌对网站进行身份验证,则需要使用相同的machineKey或将它们都放在同一台服务器上

您需要将machineKey添加到
system.web
部分,如下所示:

Web.Config

<system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <machineKey validationKey="*****" decryptionKey="***" validation="SHA1" decryption="AES" />
</system.web>

希望这对你有用。

好吧,我已经为此工作了一段时间,我终于找出了问题所在,现在它开始工作了

GrantResourceOwnerCredentials方法上的Cors启用代码似乎以某种方式推翻了参数中的标题。因此,通过将第一行放在当前第三行的正下方,您将解决您的问题:

    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

    IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);

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

这篇文章发表一年后,我也遇到了同样的问题

如您所见,我的承载令牌在请求头中被识别,但我的身份仍然没有得到验证


要解决这个问题,简短的回答是,在配置WebApi中间件(HttpConfiguration)之前,请确保配置OAuth中间件。

Microsoft在发布如此难看的复杂性时犯了一个错误。。。我花了大约两天的时间试图找到同一问题的解决方案……我也花了很多时间试图找到解决方案。如果你能解决这个问题,请告诉我,我们三个人。这种OWIN实现比WCF的第一个版本更糟糕。我的天啊,他们能做得有多艰难?不管我怎么想。我必须仔细阅读源代码,这是一个冗长的解释。如果有人关心它,我会在这里编辑我的帖子。但简单的回答是,在配置webapi中间件(HttpConfiguration)之前,只需配置oauth中间件即可。@adOran如果能提供更多信息,我将不胜感激,我可以看到我的中间件在webapi配置之后启动。您更改此顺序的方法是什么?@TheAssetor在您的owin启动中,您需要做的就是在web api之前定义授权提供程序。所以基本上,((IAppBuilder)app);((IAppBuilder)app.UseWebApi()。这里的顺序之所以重要,是因为AuthorizationAttribute取决于事先定义的AuthenticationManager。我已将api抽象为类,因此最终由类驱动是否需要身份验证。[Authorize]属性是绝对要求吗?我试着在可能的情况下不再使用它!我刚刚向api本身添加了authorize属性,现在框架直接拒绝了我的授权头,所以我的jwt一定是格式不正确,放在错误的位置,或者与其他身份验证机制混在一起。不知道我做错了什么!这正是我所需要的代码工作良好。非常感谢你。我会写一篇文章来解释在我不忙的时候它是如何工作的。
    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

    IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);

   context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
    function userAccount($resource, appSettings) {
    return {
        registration: $resource(appSettings.serverPath + "/api/Account/Register", null, 
                {
                    'registerUser' : { method : 'POST'}
                }
            ),
        login : $resource(appSettings.serverPath + "/Token", null, 
                {
                    'loginUser': {
                        method: 'POST',
                        headers: {
                            'Content-Type' : 'application/x-www-form-urlencoded' 
                        },
                        transformRequest: function (data, headersGetter) {
                            var str = [];
                            for (var d in data) {
                                str.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
                            }
                            return str.join("&"); 
                        }
                    }
                } 
            )
    }
}