ASP.NET Core 1.0 OAuth-сервер с использованием Openiddict
Я хотел бы использовать OAuth Openiddict для защиты конечных точек API в моем веб-приложении ASP.NET Core 1.0. api
конечные точки будут вызываться приложением телефона, и пользователи должны войти в систему с именем пользователя и паролем.
Поток идет так:
- Пользователь может зарегистрироваться и войти через веб-приложение:
https://www.domain.com
- Пользователь устанавливает приложение телефона, и они могут войти и зарегистрироваться, используя приложение телефона. Вход, регистрация и доступ к данным осуществляется через
api
конечные точки: пример:https://www.domain.com/api/service/getsomedata
Как настроить OAuth Openiddict, чтобы защитить конечные точки API с помощью OAuth?
2 ответа
Как настроить OAuth Openiddict, чтобы защитить конечные точки API с помощью OAuth?
Ваш сценарий звучит как хороший кандидат на получение простого гранта "пароль владельца ресурса", который по сути является эквивалентом базовой аутентификации OAuth2 или форм.
Вот что я бы порекомендовал:
Создать новый AccountController
/ RegistrationController
Контроллер API, отвечающий за создание новых учетных записей:
Поскольку на данном этапе учетная запись пользователя не существует, вы не можете использовать токен аутентификации здесь (так же, как по умолчанию AccountController.Register
шаблон не может требовать проверки подлинности куки перед регистрацией пользователя).
Сконфигурируйте 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 для защиты ваших API:
Чтобы включить аутентификацию токена, обратитесь к AspNet.Security.OAuth.Validation
1.0.0-alpha2-final пакет и добавить app.UseOAuthValidation()
до app.UseMvc()
, Чтобы сделать аутентификацию обязательной, просто используйте [Authorize]
атрибут, как вы делаете с аутентификацией куки.
Не стесняйтесь играть с этим образцом. Он не использует мобильное приложение для клиентской части, но вы должны легко понять, как оно работает.
Для получения дополнительной информации вы также можете прочитать это сообщение в блоге, написанное Майком Русосом для блога Microsoft .NET по веб-разработке и инструментам: Аутентификация на токене на предъявителя в 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 и выдаче GET для http://domain.com/api/service/getdata возвращалось значение 302 и перенаправление на учетную запись / логин. Если я удалю app.UseIdentity(), то if вернет 401 Unauthorized, но пользователь не сможет больше войти в систему с помощью пользовательского интерфейса http://domain.com/. Добавление этого [Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
чтобы мой ServiceController решил проблему.
@Pinpoint, в чем выгода app.UseOAuthValidation()?