c# - 如何跨多个服务器在 OWIN 中为 IIS 使用 OAuth AccessTokenFormat?

标签 c# asp.net authentication iis owin

我正在使用 C# 开发 Web 应用程序。 目前,(承载)身份验证和 token 生成都在一个地方发生。

理赔完成后,我们有以下代码可以拿到票:-

var ticket = new AuthenticationTicket(identity, properties);
context.Validated(ticket);

稍后,我们检查传回给我们的票,使用以下代码获取票:-

OAuthAuthenticationOptions.AccessTokenFormat.Unprotect(token);

当代码全部托管在一台机器上时,这一切都很好。

当我拆分代码以在不同的机器上工作时,我无法通过调用 AccessTokenFormat.Unprotect 方法取回 AuthenticationTicket。

看完这篇文章OWIN Bearer Token Authentication - 我尝试在新机器的 web.config 文件中设置 MachineKey 以匹配现有服务器的 MachineKey。

结果是解密过程不再抛出错误,但它为 token 返回null。

(当我没有正确的 machineKey 时,出现解密运行时错误。)

如果我在这里犯了一个明显的错误,请有人告诉我吗?

另外,由于我是 OWIN 管道的新手;新项目中可能缺少一个配置步骤。

谢谢, 大卫:-)

2016-05-23:Startup.Configuration 中的代码

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // Build IoC Container
        var container = new Container().Initialize();

        // Initialize Logging and grab logger.
        MyCustomLogger.Configure();
        var logger = container.GetInstance<IMyCustomLogger>();
        var userIdProvider = container.GetInstance<IUserIdProvider>();
        var azureSignalRInterface = new SignalRInterface();

        GlobalHost.DependencyResolver.Register(typeof(ITokenService), container.GetInstance<ITokenService>);
        GlobalHost.DependencyResolver.Register(typeof(IMyCustomLogger), () => logger);
        GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => userIdProvider);
        GlobalHost.DependencyResolver.Register(typeof(IExternalMessageBus), () => azureSignalRInterface);
        GlobalHost.DependencyResolver.Register(typeof(ISerializer<>), () => typeof(JsonSerializer<>));

        app.Use<ExceptionHandlerMiddleware>(logger, container);
        app.Use<StructureMapMiddleware>(container);

        // Setup Authentication
        var authConfig = container.GetInstance<OwinAuthConfig>();
        authConfig.ConfigureAuth(app);

        // Load SignalR
        app.MapSignalR("/signalR", new HubConfiguration()
        {
            EnableDetailedErrors = false,
            EnableJSONP = true,
            EnableJavaScriptProxies = true
        });
    }
}

Container().Initialize 只是使用以下代码为 StructureMap 的依赖注入(inject)设置了一些注册表:-

    public static IContainer Initialize(this IContainer container)
    {
        container.Configure(x => {
            x.AddRegistry<ServiceRegistry>();
            x.AddRegistry<AlertsRegistry>();
            x.AddRegistry<SignalRRegistry>();
        });
        return container;
    }

此外,我的 Global.asax.cs 文件如下所示:-

    protected void Application_Start()
    {
        //GlobalConfiguration.Configure(WebApiConfig.Register);
        GlobalConfiguration.Configure(config =>
        {
            AuthConfig.Register(config);
            WebApiConfig.Register(config);
        });
    }

AuthConfig 类如下所示:-

public static class AuthConfig
{
    /// <summary>
    /// Registers authorization configuration with global HttpConfiguration.
    /// </summary>
    /// <param name="config"></param>
    public static void Register(HttpConfiguration config)
    {
        // Forces WebApi/OAuth to handle authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
    }
}

其中 OAuthDefaults.AuthenticationType 是字符串常量。

最后,我的OwinAuthConfig代码如下:-

public class OwinAuthConfig
{

    public static OAuthAuthorizationServerOptions OAuthAuthorizationOptions { get; private set; }
    public static OAuthBearerAuthenticationOptions OAuthAuthenticationOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the application for OAuth based flow
        PublicClientId = "MyCustom.SignalRMessaging";
        OAuthAuthorizationOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Authenticate"), // PathString.FromUriComponent("https://dev.MyCustom-api.com/Authenticate"),
            Provider = new MyCustomDbLessAuthorizationProvider(
                PublicClientId),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),

            // TODO: change when we go to production.
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthAuthorizationServer(OAuthAuthorizationOptions);

        OAuthAuthenticationOptions = new OAuthBearerAuthenticationOptions
        {
            Provider = new MyCustomDbLessAuthenticationProvider()
        };

        app.UseOAuthBearerAuthentication(OAuthAuthenticationOptions);
    }

    public static AuthenticationTicket UnprotectToken(string token)
    {
        return OAuthAuthenticationOptions.AccessTokenFormat.Unprotect(token);
    }

    public void ConfigureHttpAuth(HttpConfiguration config)
    {
        config.Filters.Add(new AuthorizeAttribute());
    }
}

2016-05-26:添加了配置文件片段。 所以这是生成 token 的服务器上的配置:-

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

这是尝试使用 token 的 SignalR 服务器上的配置:-

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

最佳答案

在资源服务器中你应该使用OAuthBearerAuthenticationOptions.AccessTokenFormat属性而不是 OAuthAuthorizationServerOptions.AccessTokenFormat .查看文档链接。

对于 IAuthenticationTokenProvider.Receive() 方法中的 AuthenticationTokenReceiveContext,您还可以执行 context.DeserializeTicket(context.Token);

正如您所指出的,两台服务器中的 MachineKey 应该相同。

希望对您有所帮助。

编辑 (2016-05-24)

public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
    context.DeserializeTicket(context.Token);
    // Now you can access to context.Ticket
    ...
}

关于c# - 如何跨多个服务器在 OWIN 中为 IIS 使用 OAuth AccessTokenFormat?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37027927/

相关文章:

c# - 从一种方法访问全局声明的字符串变量会给出 null 值

c# - BlockingCollection 最大大小

c# - 如何在C#中绘制蜡烛图

c# - 在 WebBrowser 控件中鼠标处于非事件状态一定时间后隐藏鼠标光标

c# - 如何跳过最后 2 条记录并使用 linq 获取所有其他记录?

asp.net - 将不同的用户重定向到另一个 URL

c# - 为什么 PageMethods 调用不起作用?

python - 在 python 中连接到 url

api - 我应该为我的 API 使用哪种身份验证策略?

firebase - Google 登录弹出窗口自动选择让我登录的用户