【问题标题】:Owin Unauthorised when hosting more web apis inside IIS website在 IIS 网站内托管更多 Web API 时 Owin 未经授权
【发布时间】:2015-04-16 06:46:06
【问题描述】:

让我们描述一下我的架构,我有一个根 IIS 网站,然后是使用 Owin 进行身份验证的 Web Api,然后是 AngularJS 前端和另一个 Web Api 来为这个前端提供服务。 看起来像:

Website(root) -
  Auth(Web API Owin)
  Front-End(AngularJS) -
    Service(Web API)

我的问题如下: - 我可以从前端的 Web Api Owin 应用程序获取令牌 - 当我尝试在服务 web api“服务”时对控制器使用此令牌时,我得到了未经授权的响应

我尝试了各种web api auth配置组合,所有站点都在同一台机器上,我在web.config中没有使用MachineKey。

配置如下: Web Api Owin:

public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCors(CorsOptions.AllowAll);

        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

        OAuthBearerAuthenticationOptions OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
            AllowInsecureHttp = true
        };

        app.UseOAuthAuthorizationServer(OAuthOptions);
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
    }
}
public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }
}

服务网络接口:

public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
    public static string PublicClientId { get; private set; }
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

        OAuthBearerAuthenticationOptions OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

    }
public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);

        // use cors with signalR
        app.Map("/signalr", map =>
            {
                // Setup the CORS middleware to run before SignalR.
                // By default this will allow all origins. You can 
                // configure the set of origins and/or http verbs by
                // providing a cors options with a different policy.
                map.UseCors(CorsOptions.AllowAll);
                var hubConfiguration = new HubConfiguration
                {
                    EnableDetailedErrors = true
                    // You can enable JSONP by uncommenting line below.
                    // JSONP requests are insecure but some older browsers (and some
                    // versions of IE) require JSONP to work cross domain
                    // EnableJSONP = true
                };
                // Run the SignalR pipeline. We're not using MapSignalR
                // since this branch already runs under the "/signalr"
                // path.
                map.RunSignalR(hubConfiguration);
            });
    }
}

我正在使用自己的 OAuthProvider,如下所示:

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
    private readonly string _publicClientId;

    public ApplicationOAuthProvider(string publicClientId)
    {
        if (publicClientId == null)
        {
            throw new ArgumentNullException("publicClientId");
        }

        _publicClientId = publicClientId;
    }

    public override Task MatchEndpoint(OAuthMatchEndpointContext context)
    {
        if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization" });
            context.RequestCompleted();
            return Task.FromResult(0);
        }
        return base.MatchEndpoint(context);
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

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

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

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

        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);

        oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
        if (user.Roles != null && user.Roles.Count != 0)
            oAuthIdentity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.Select(r => r.RoleId).Aggregate((acc, r) => acc + ";" + r)));
        oAuthIdentity.AddClaim(new Claim("TwoFactorExpiration", user.TwoFactorExpiration.ToString()));

        ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
            CookieAuthenticationDefaults.AuthenticationType);

        AuthenticationProperties properties = CreateProperties(user.UserName);
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
        context.Request.Context.Authentication.SignIn(cookiesIdentity);
    }

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

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

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        // Resource owner password credentials does not provide a client ID.
        if (context.ClientId == null)
        {
            context.Validated();
        }

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

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (context.ClientId == _publicClientId)
        {
            Uri expectedRootUri = new Uri(context.Request.Uri, "/");

            if (expectedRootUri.AbsoluteUri == context.RedirectUri)
            {
                context.Validated();
            }
        }

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

    public static AuthenticationProperties CreateProperties(string userName)
    {
        IDictionary<string, string> data = new Dictionary<string, string>
        {
            { "userName", userName }
        };
        return new AuthenticationProperties(data);
    }
}

如您所见,我也在服务 Web api 上使用了 SignalR。 如果每个 web api 在 IIS 上都有自己的网站,那么一切都很好。

我做错了什么?我知道我错过了一些东西。目的是使用一个 web api owin 应用程序来授权许多 web api,正如您所见,我在那里也定义了基于角色的身份验证。

感谢您的任何意见。

更新 1: 当我尝试通过 Visual Studio 调试我的 IIS 网站时,我在调试窗口中收到以下消息:

System.Web.dll 中发生了“System.Security.Cryptography.CryptographicException”类型的第一次机会异常

...

w3wp.exe 信息:0:Operation=AuthorizeAttribute.OnAuthorizationAsync,Status=401(未授权)

w3wp.exe 信息:0 : Message='Selected action 'Get(Nullable1 affiliateId, Nullable1 date)'', Operation=ApiControllerActionSelector.SelectAction

w3wp.exe 信息:0:Operation=AffiliatesController.ExecuteAsync,Status=401(未授权)

w3wp.exe 信息:0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance

w3wp.exe 信息:0:Operation=CorsMessageHandler.SendAsync,Status=401(未授权)

w3wp.exe 信息:0 : Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate

w3wp.exe 信息:0:Operation=AuthorizeAttribute.OnAuthorizationAsync,Status=401(未授权)

【问题讨论】:

    标签: c# api oauth signalr owin


    【解决方案1】:

    我找到了解决方案,即使您的解决方案在同一台机器上,您也必须为您的机器创建机器密钥并将其附加到您的网络配置中,请按照以下步骤 5: http://bitoftech.net/2014/09/24/decouple-owin-authorization-server-resource-server-oauth-2-0-web-api/

    当每个 web api 都有自己的 IIS 网站时,我仍然不知道为什么它可以工作。

    【讨论】:

      猜你喜欢
      • 2014-04-18
      • 2018-06-06
      • 2014-05-24
      • 2017-12-09
      • 1970-01-01
      • 2019-10-13
      • 2017-11-09
      • 1970-01-01
      • 2011-05-18
      相关资源
      最近更新 更多