前回からのあらすじ
前回:ASP.NET Core 2 API x Identity でユーザー登録とアクセスを管理(JWT) 1.準備編
前回はASP.NET Core 2 API x Identityを使うための準備をしました。
今回は、Identity ライブラリーを使って実際に利用するメソッドを書いていきます。今日は一旦ユーザーを作成するところから。
メソッド一覧
ユーザーを管理するためのメソッド
名前 | 利用用途 |
---|---|
CreateUser | ユーザーを作成(登録) |
UpdateUser | ユーザー情報、名前などのプロフィール系データの更新 |
ChangePassword | パスワードの更新 |
EmailConfirmToken | メールアドレス確認時に利用するトーケンを生成 |
DeleteUser | ユーザー情報の削除 |
AddToRole | ロールに追加 |
RemoveFromRole | ロールを削除 |
FindUsers | ユーザーを検索 |
GetUser | ユーザーデータを取得 |
ロールを管理するためのメソッド
名前 | 利用用途 |
---|---|
CreateRole | ユーザーを作成(登録) |
DeleteRole | ユーザー情報、名前などのプロフィール系データの更新 |
InRole | ロール内のユーザー一覧を返す |
モデルの準備
ユーザーを新しく登録するために必要なモデルを準備します。 API経由でのリクエストモデル、レスポンスモデルを用意します。
データモデル
前章のモデルに加え、アカウント作成時間を追加しました。DBの更新も忘れずに!
using System;
using Microsoft.AspNetCore.Identity;
namespace SampleApi.Models.ApplicationUsers.DataModels
{
public class ApplicationUserDataModel : IdentityUser
{
public DateTime Created { get; set; }
}
}
リクエストモデル
using SampleApi.Models.ApplicationUsers.DataModels;
namespace SampleApi.Models.ApplicationUsers.RequestModels
{
public class ApplicationUserRequestModel
{
public ApplicationUserDataModel CreateUserRequestModelToApplicationUserDateModel(
CreateUserRequestModel user)
{
return new ApplicationUserDataModel()
{
UserName = user.UserName,
Email = user.Email
};
}
}
public class CreateUserRequestModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
}
レスポンスモデル
using System;
using System.Collections.Generic;
using SampleApi.Models.ApplicationUsers.DataModels;
namespace SampleApi.Models.ApplicationUsers.ResponseModels
{
public class ApplicationUserResponseModel
{
/// <summary>
/// From ApplicationUserDataModel to CreateUserResponseModel
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public CreateUserResponseModel ApplicationUserDataModelToCreateUserRequestMode(
ApplicationUserDataModel user)
{
var response = new CreateUserResponseModel()
{
UserName = user.UserName,
Email = user.Email,
Created = user.Created
};
return response;
}
}
public class CreateUserResponseModel
{
public string UserName { get; set; }
public string Email { get; set; }
public DateTime Created { get; set; }
public List<CreateUserErrorResponseModel> Errors { get; set; }
}
public class CreateUserErrorResponseModel
{
public string ErrorCode { get; set; }
public string ErrorMessage { get; set; }
}
}
Handlerの作成
上記で定義したメソッドの詳細を次のクラスでまとめます。コントローラーから呼ばれて使われる想定です。
using System;
using System.Collections.Generic;
using SampleApi.Handlers.Accounts.Interfaces;
using SampleApi.Models.ApplicationUsers.DataModels;
using SampleApi.Models.ApplicationUsers.RequestModels;
using SampleApi.Models.ApplicationUsers.ResponseModels;
using Microsoft.AspNetCore.Identity;
using System.Threading.Tasks;
namespace SampleApi.Handlers.Accounts
{
/// <summary>
/// Handles all account related operations
/// </summary>
public class AccountHandler : IAccountHandler
{
private readonly UserManager<ApplicationUserDataModel> _userManager;
public AccountHandler(UserManager<ApplicationUserDataModel> userManager)
{
_userManager = userManager;
}
/// <summary>
/// Create new user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public async Task<CreateUserResponseModel> Create(CreateUserRequestModel user)
{
// Request model
ApplicationUserRequestModel request = new ApplicationUserRequestModel();
// Request model to data model
ApplicationUserDataModel applicationUser = request.CreateUserRequestModelToApplicationUserDateModel(user);
// Timestamping
applicationUser.Created = DateTime.UtcNow;
// Create new user
IdentityResult newUser = await _userManager.CreateAsync(
applicationUser,
user.Password);
if (newUser.Succeeded)
{
// Response model
ApplicationUserResponseModel response = new ApplicationUserResponseModel();
// Return created user
return response.ApplicationUserDataModelToCreateUserRequestMode(applicationUser);
}
// Error
CreateUserResponseModel errorResponse = new CreateUserResponseModel();
if (newUser.Errors != null)
{
errorResponse.Errors = new List<CreateUserErrorResponseModel>();
foreach (var error in newUser.Errors)
{
errorResponse.Errors.Add(
new CreateUserErrorResponseModel()
{
ErrorCode = error.Code,
ErrorMessage = error.Description
});
}
}
return errorResponse;
}
}
}
DI
Startup.cs にて今回新しく追加したHandlerが使えるようにDIします。また、ユーザー作成時のオプションプロパティーを設定しています。
using SampleApi.Filters;
using SampleApi.Handlers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.IO;
using System.Reflection;
using SampleApi.Handlers.Accounts;
using SampleApi.Handlers.Accounts.Interfaces;
using SampleApi.Models.ApplicationUsers.DataModels;
using Microsoft.AspNetCore.Identity;
namespace SampleApi
{
public class Startup
{
public Startup(IConfiguration configuration, IOptions<AppSettings> optionsAccessor)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//Sql
services.AddDbContext<JetonModelContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("UserDabtaseConnection")));
services.AddIdentity<ApplicationUserDataModel, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserManager<UserManager<ApplicationUserDataModel>>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(
options =>
{
// Password settings
options.Password.RequireDigit = false;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Password.RequiredUniqueChars = 3;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings
options.User.RequireUniqueEmail = true;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IAccountHandler, AccountHandler>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info
{
Title = "{title}",
Version = "1",
Description = "{description}",
Contact = new Contact
{
Name = "{name}",
Email = "{email}",
Url = "{url}"
}
});
c.OperationFilter<AddAuthorizationHeaderParameterOperationFilter>();
// Set the comments path for the Swagger JSON and UI.
string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
string xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jeton API V1");
c.RoutePrefix = string.Empty;
});
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
}
}
}
Controllerの作成
では・・やっとControllerを追加します。
using System.Threading.Tasks;
using SampleApi.Handlers.Accounts.Interfaces;
using SampleApi.Models.ApplicationUsers.RequestModels;
using SampleApi.Models.ApplicationUsers.ResponseModels;
using Microsoft.AspNetCore.Mvc;
namespace SampleApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
private readonly IAccountHandler _accountHandler;
public AccountController(IAccountHandler accountHandler)
{
_accountHandler = accountHandler;
}
[HttpPost, Route("/Account/CreateUser")]
public async Task<ActionResult<CreateUserResponseModel>> Create([FromBody] CreateUserRequestModel user)
{
var response = await _accountHandler.Create(user);
return response ;
}
}
}
Swaggerからアカウント作成
Swaggerから新しいアカウントを作成してみましょう。
まずは正常系のリクエスト・レスポンスを試してみます。
正常リクエスト
正常レスポンス
DBの中身確認
DBの中身を確認すると新しいユーザーが生成されていることを確認しました。
異常系リクエスト
では異常系リクエストを試してみます。
異常系レスポンス
パスワードは少なくても6文字、3文字ユニークでないといけないとのことです。
次
アカウントが作成できたので、次はログインとトークンを発行してみましょう。
次回:ASP.NET Core 2 API x Identity でユーザー登録とアクセスを管理(JWT) 2. 基本メソッド編 (ログイン)