ASP.NET 使用 Openiddict 的核心 1.0 OAuth 服务器
ASP.NET Core 1.0 OAuth Server using Openiddict
我想使用 Openiddict OAuth 来保护我的 ASP.NET Core 1.0 Web 应用程序中的 api 端点。 api
端点将由 phone 应用程序调用,用户必须使用用户名和密码登录。
流程是这样的:
- 用户可以通过网络应用程序注册和登录:
https://www.domain.com
- 用户安装phone应用程序,他们可以使用phone应用程序登录和注册。登录、注册和数据访问是通过
api
个端点完成的:示例:https://www.domain.com/api/service/getsomedata
如何配置 Openiddict OAuth,以便使用 OAuth 保护 API 端点?
How can I configure Openiddict OAuth so I can protect the API endpoints using OAuth?
您的方案听起来很适合 the simple "resource owner password credentials" grant,它基本上是基本或表单身份验证的 OAuth2 等价物。
以下是我的推荐:
创建一个新的AccountController
/RegistrationController
API负责创建新账户的控制器:
由于这个阶段用户账号不存在,这里不能使用token认证(就像默认的AccountController.Register
模板在用户注册前不能要求cookies认证一样)。
配置 OpenIddict 以启用令牌端点并允许资源所有者密码凭据授予:
services.AddOpenIddict<ApplicationDbContext>()
// Disable the HTTPS requirement during development.
.DisableHttpsRequirement()
// Enable the token endpoint, required to use
// the resource owner password credentials grant.
.EnableTokenEndpoint("/connect/token")
// Enable the password and the refresh token flows.
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
使用 OAuth2 验证中间件来保护您的 APIs:
要启用令牌认证,请参考AspNet.Security.OAuth.Validation
1.0.0-alpha2-final 包并在app.UseMvc()
之前添加app.UseOAuthValidation()
。要强制进行身份验证,只需像使用 cookie 身份验证一样使用 [Authorize]
属性。
不要犹豫,一起玩 this sample。它的客户端部分不使用移动应用程序,但您应该很容易理解它是如何工作的。
有关详细信息,您还可以阅读 Mike Rousos 为 Microsoft .NET Web 开发和工具博客撰写的博客 post:Bearer Token Authentication in ASP.NET Core
好的,感谢@Pinpoint 为我指明了正确的方向。
但是这是我的 Startup.cs 配置:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddOpenIddict<ApplicationUser, ApplicationRole, ApplicationDbContext>()
.DisableHttpsRequirement()
.EnableTokenEndpoint("/connect/token")
.AllowPasswordFlow()
.AllowRefreshTokenFlow()
.UseJsonWebTokens();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseOpenIddict();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
Audience = "http://localhost:24624/",
Authority = "http://localhost:24624/"
});
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
ApplicationDbContext.cs:
public class ApplicationDbContext : OpenIddictDbContext<ApplicationUser, ApplicationRole>
{
public ApplicationDbContext(DbContextOptions options)
: base(options)
{
Database.EnsureCreated();
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
ApplicationRole.cs:
public class ApplicationRole : IdentityRole
{
}
ApplicationUser.cs:
public class ApplicationUser : OpenIddictUser
{
}
ServiceController.cs:
[Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
[Route("api/service")]
public class ServiceController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public ServiceController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
[Route("getdata")]
public async Task<IActionResult> GetData()
{
var user = await _userManager.GetUserAsync(User);
if (user == null) return Ok("No user / not logged in");// if Authorize is not applied
return Ok(user);
}
}
这里的关键是ServiceController.cs:[Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
@Pinpoint:我没有使用 app.UseOAuthValidation() 因为它返回 302 并重定向到 Account/Login。
所以现在它是这样工作的:
- 访问 http://domain.com,用户可以注册、登录、查看数据等
- 用户可以下载移动应用程序、注册、登录和获取数据
在 api 端实现用户注册登录非常简单直接。
问题是使用 fiddler 并向 http://domain.com/api/service/getdata 发出 GET 返回 302 并重定向到 Account/Login。如果我删除 app.UseIdentity(),那么如果将返回 401 Unauthorized 但用户将无法再使用 UI http://domain.com 登录。将此 [Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
添加到我的 ServiceController 解决了问题。
@Pinpoint app.UseOAuthValidation() 的好处是什么?
我想使用 Openiddict OAuth 来保护我的 ASP.NET Core 1.0 Web 应用程序中的 api 端点。 api
端点将由 phone 应用程序调用,用户必须使用用户名和密码登录。
流程是这样的:
- 用户可以通过网络应用程序注册和登录:
https://www.domain.com
- 用户安装phone应用程序,他们可以使用phone应用程序登录和注册。登录、注册和数据访问是通过
api
个端点完成的:示例:https://www.domain.com/api/service/getsomedata
如何配置 Openiddict OAuth,以便使用 OAuth 保护 API 端点?
How can I configure Openiddict OAuth so I can protect the API endpoints using OAuth?
您的方案听起来很适合 the simple "resource owner password credentials" grant,它基本上是基本或表单身份验证的 OAuth2 等价物。
以下是我的推荐:
创建一个新的AccountController
/RegistrationController
API负责创建新账户的控制器:
由于这个阶段用户账号不存在,这里不能使用token认证(就像默认的AccountController.Register
模板在用户注册前不能要求cookies认证一样)。
配置 OpenIddict 以启用令牌端点并允许资源所有者密码凭据授予:
services.AddOpenIddict<ApplicationDbContext>()
// Disable the HTTPS requirement during development.
.DisableHttpsRequirement()
// Enable the token endpoint, required to use
// the resource owner password credentials grant.
.EnableTokenEndpoint("/connect/token")
// Enable the password and the refresh token flows.
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
使用 OAuth2 验证中间件来保护您的 APIs:
要启用令牌认证,请参考AspNet.Security.OAuth.Validation
1.0.0-alpha2-final 包并在app.UseMvc()
之前添加app.UseOAuthValidation()
。要强制进行身份验证,只需像使用 cookie 身份验证一样使用 [Authorize]
属性。
不要犹豫,一起玩 this sample。它的客户端部分不使用移动应用程序,但您应该很容易理解它是如何工作的。
有关详细信息,您还可以阅读 Mike Rousos 为 Microsoft .NET Web 开发和工具博客撰写的博客 post:Bearer Token Authentication in ASP.NET Core
好的,感谢@Pinpoint 为我指明了正确的方向。
但是这是我的 Startup.cs 配置:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddOpenIddict<ApplicationUser, ApplicationRole, ApplicationDbContext>()
.DisableHttpsRequirement()
.EnableTokenEndpoint("/connect/token")
.AllowPasswordFlow()
.AllowRefreshTokenFlow()
.UseJsonWebTokens();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseOpenIddict();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
Audience = "http://localhost:24624/",
Authority = "http://localhost:24624/"
});
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
ApplicationDbContext.cs:
public class ApplicationDbContext : OpenIddictDbContext<ApplicationUser, ApplicationRole>
{
public ApplicationDbContext(DbContextOptions options)
: base(options)
{
Database.EnsureCreated();
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
ApplicationRole.cs:
public class ApplicationRole : IdentityRole
{
}
ApplicationUser.cs:
public class ApplicationUser : OpenIddictUser
{
}
ServiceController.cs:
[Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
[Route("api/service")]
public class ServiceController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public ServiceController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
[Route("getdata")]
public async Task<IActionResult> GetData()
{
var user = await _userManager.GetUserAsync(User);
if (user == null) return Ok("No user / not logged in");// if Authorize is not applied
return Ok(user);
}
}
这里的关键是ServiceController.cs:[Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
@Pinpoint:我没有使用 app.UseOAuthValidation() 因为它返回 302 并重定向到 Account/Login。
所以现在它是这样工作的:
- 访问 http://domain.com,用户可以注册、登录、查看数据等
- 用户可以下载移动应用程序、注册、登录和获取数据
在 api 端实现用户注册登录非常简单直接。
问题是使用 fiddler 并向 http://domain.com/api/service/getdata 发出 GET 返回 302 并重定向到 Account/Login。如果我删除 app.UseIdentity(),那么如果将返回 401 Unauthorized 但用户将无法再使用 UI http://domain.com 登录。将此 [Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
添加到我的 ServiceController 解决了问题。
@Pinpoint app.UseOAuthValidation() 的好处是什么?