使用 Katana 和 MembershipReboot 实现简单的 Oauth 服务器

发布日期:2026-07-12 03:51:04   来源 : 杭州电子商务研究院    浏览量 :4
杭州电子商务研究院 发布日期:2026-07-12 03:51:04  
4

介绍

在我之前关于 .NET 的文章中,我介绍了如何使用 ASP.NET MVC 中的 MembershipReboot 保护和管理用户帐户。在这篇文章中,我将引导您在 ASP.NET Web API 中实现资源所有者密码凭据授予类型。

如果您正在阅读本文,我会假设您对 ASP.NET 中的 Owin(开放 Web 接口)中间件有相当多的了解,并且您非常了解 OAuth2 和 Katana。如果您需要复习上述任何内容,请看这里。

我不会介绍这些主题,但我会提供您可以添加到 ASP.NET 项目的代码。这样,您将能够使用此授权类型专门保护对您服务的访问。

资源所有者密码凭证授权类型适用于资源所有者(拥有特定资源的应用程序用户)与我们要保护的 Web 服务的客户端(代表资源所有者请求访问资源的应用程序)具有信任关系的情况。有关授权类型重要性的更多信息,请查看OAuth2 页面

首先,让我们安装以下 nuget 包。

安装 Nuget 包

  • 首先安装依赖注入容器SimpleInjector

安装包 SimpleInjector.Integration.WebApi

  • 然后安装 MembershipReboot 的软件包。

安装包 BrockAllen.MembershipReboot.Owin

安装包 BrockAllen.MembershipReboot.Ef

配置

配置 MembershipReboot 和 DI 容器并注册用于在运行时解析依赖项的容器

接下来是配置我们之前添加的框架。我将首先在web.config文件中向存储用户凭据的数据库添加连接字符串。

      <add name="MembershipReboot" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=MembershipRebootWebAPI;Integrated Security=True" providerName="System.Data.SqlClient" />
    

在代码中配置 MembershipReboot

让我们配置 MembershipReboot。我通常喜欢在代码中执行此操作,并将其放在App_Start文件夹中的文件中

在App_Start文件夹中添加一个名为MembershipRebootConfig的文件,内容如下:

      using BrockAllen.MembershipReboot;

public class MembershipRebootConfig
{
	public static MembershipRebootConfiguration Create()
	{
		var config = new MembershipRebootConfiguration
		{
			MultiTenant = true,
			RequireAccountVerification = true,
			EmailIsUsername = true,
			AllowLoginAfterAccountCreation = true
		};

		return config;
	}
}
    

上面,我启用了多个租户,因为用户帐户将存储在一个租户上,而 API 客户端凭据将存储在另一个租户上。文件中的其他设置可以根据需要进行修改。添加此文件是可选的,因为您可以在 web.config 文件中添加相同的设置。

配置 SimpleInjector

之后,配置 SimpleInjector 以在运行时解析 MembershipReboot 的类。在App_Start文件夹中添加一个名为的新类,其中包含以下内容

      public static class SimpleInjectorWebApiInitializer
{
	/// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
	public static void Initialize(IAppBuilder app)
	{
		var container = new Container();
		container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();

		InitializeContainer(container);

		container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

		container.Verify();

		GlobalConfiguration.Configuration.DependencyResolver =
			new SimpleInjectorWebApiDependencyResolver(container);

        //allow scoped instances to be resolved during an OWIN request
		app.Use(async (context, next) =>
		{
			using (container.BeginExecutionContextScope())
			{
			    context.Environment.SetUserAccountService(() => container.GetInstance<UserAccountService>());
				await next();
			}
		});
	}

	private static void InitializeContainer(Container container)
	{
		System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());

		container.RegisterSingleton<MembershipRebootConfiguration>(MembershipRebootConfig.Create);
		container.Register<DefaultMembershipRebootDatabase>(() => new DefaultMembershipRebootDatabase(), Lifestyle.Scoped);

		var defaultAccountRepositoryRegistration =
			Lifestyle.Scoped.CreateRegistration<DefaultUserAccountRepository>(container);

		container.AddRegistration(typeof(IUserAccountQuery), defaultAccountRepositoryRegistration);
		container.AddRegistration(typeof(IUserAccountRepository), defaultAccountRepositoryRegistration);
		container.Register<UserAccountService>(() => new UserAccountService(container.GetInstance<MembershipRebootConfiguration>(), container.GetInstance<IUserAccountRepository>()), Lifestyle.Scoped);
	}
}
    

上面,我已经注册了 MembershipReboot 的依赖项,并且还添加了代码以使 SimpleInjector 在 Owin 请求期间解析依赖项。

打开 Owin 启动类并调用Initialize

      //Startup.cs
public void Configuration(IAppBuilder app)
{
    SimpleInjectorWebApiInitializer.Initialize(app);
}
    

OAuth2 令牌端点设置

接下来,我们需要使用Microsoft.Owin.Security.OAuth库附带的OAuthAuthorizationServerMiddleware设置 OAuth 2.0 令牌端点以支持资源所有者密码凭据授予类型。这需要一个授权服务器,然后将其连接到 Katana 管道。

使用 Katana 编写授权服务器围绕从OAuthAuthorizationServerProvider派生的类,该类包含允许我们操作 OAuth2 协议的方法。

为此,我将添加一个名为MyOAuthAuthorizationServerProvider的类,它派生自OAuthAuthorizationServerProvider并重写方法 ValidateClientAuthentication 和 GrantResourceOwnerCredentials。

      public class MyOAuthAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
	public override System.Threading.Tasks.Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
	{
		string cid, csecret;
		if (context.TryGetBasicCredentials(out cid, out csecret))
		{
			var svc = context.OwinContext.Environment.GetUserAccountService<UserAccount>();
			if (svc.Authenticate("clients", cid, csecret))
			{
				context.Validated();
			}
		}
		return Task.FromResult<object>(null);
	}

	public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
	{
		var svc = context.OwinContext.Environment.GetUserAccountService<UserAccount>();
		UserAccount user;
		if (svc.Authenticate("users", context.UserName, context.Password, out user))
		{
			var claims = user.GetAllClaims();

			var id = new System.Security.Claims.ClaimsIdentity(claims, "MembershipReboot");
			context.Validated(id);
		}

		return base.GrantResourceOwnerCredentials(context);
	}
}
    

在 ValidateClientAuthentication 方法中,我编写了代码来验证客户端凭据,如果凭据与数据库中的记录匹配,则调用OAuthValidateClientAuthenticationContext.Validated()方法。如果客户端通过验证,则继续验证用户或资源所有者凭据(用户名和密码),并在将传递给 GrantResourceOwnerCredentials 方法的OAuthGrantResourceOwnerCredentialsContext实例上调用 Validated() 方法。

现在我们需要将授权服务器中间件连接到 Owin 管道。IAppBuilder 上有一个简写扩展方法可以使用此中间件,即 UseOAuthAuthorizationServer。我们将使用此扩展方法在 Startup 类中配置 OAuth 2.0 端点:

      public void Configuration(IAppBuilder app)
{
    SimpleInjectorWebApiInitializer.Initialize(app);

    app.UseOAuthAuthorizationServer(new Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerOptions
    {
        AllowInsecureHttp = true,//should be disabled in production
        Provider = new MyOAuthAuthorizationServerProvider(),
        TokenEndpointPath = new PathString("/token")
    });
}
    

此外,我们将添加用于使用令牌的承载令牌身份验证中间件:

      public void Configuration(IAppBuilder app)
{
    SimpleInjectorWebApiInitializer.Initialize(app);

    app.UseOAuthAuthorizationServer(new Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerOptions
    {
        AllowInsecureHttp = true,
        Provider = new MyOAuthAuthorizationServerProvider(),
        TokenEndpointPath = new PathString("/token")
    });

    // token consumption
    var oauthConfig = new Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationOptions
    {
        AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
        AuthenticationType = "Bearer"
    };
    // Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerAuthentication(oauthConfig);
}
    

要获取令牌,我们需要向 localhost/token 发出 post 请求并传入必要的参数。例如:

      POST http://localhost:19923/token
Content-Type: Application/x-www-form-urlencoded

username=jbloggs&password=pass1234&grant_type=password
    

此时,我们将获得如下结果:

      {
  "access_token":
    "XoHocsL0wOJBVVrjvSj6GpdGD-VrPD2ainZGyeZ8ji0aTq33epyHw72POhB8evYn41fzaSnjx7eo0iclADQBWTMgnghgZdXzNoLo6hwf4Y3SiB0aPTPgZi6PJwoGQK_aMWW62770jo6PBznPrSO0AOZUIrpxjUSZze90-HJjsM9ZgATIWdIvuiICqVjW7n5Z-o0GNSoDTIm-4k2zee0-c_lifHuLmW97IbsQ3I4gMz1SCBReSJtXJc8noPHvgwhFB_qZ2R1-TxR64nUVgxYYtBAoy9n6WKTgNAqrnUwsa0jfMk6wselrLwMGq-R-6_AX4bkh16OZBTGa5hXVWoLPIHl2JTKCkO2DsX2jqvp3J7PObRkZWMyUOyzwhnQWu_XTpn4ogwtcJvLulfiA6W01s8qiUQO--Xefm38ngu5HTM4",
  "token_type": "bearer",
  "expires_in": 1199
}
    

这就是我们开始所需要的一切。如您所见,令牌具有类型和到期日期。干净又安全!我在 GitHub 上有一个示例项目

以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据