Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

[ASP.NET Core 2 Identity] APIでユーザー登録とアクセスを管理(JWT) 2. 基本メソッド編 (アカウント作成)

More than 1 year has passed since last update.

前回からのあらすじ

前回: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の更新も忘れずに!

/Models/ApplicationUsers/DataModels/ApplicationUserDataModel.cs
using System;
using Microsoft.AspNetCore.Identity;

namespace SampleApi.Models.ApplicationUsers.DataModels
{
    public class ApplicationUserDataModel : IdentityUser
    {
        public DateTime Created { get; set; }
    }
}

リクエストモデル

/Models/ApplicationUsers/RequestModels/ApplicationUserRequestModel.cs
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; }
    }
}

レスポンスモデル

/Models/ApplicationUsers/ResponseModels/ApplicationUserResponseModel.cs
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の作成

上記で定義したメソッドの詳細を次のクラスでまとめます。コントローラーから呼ばれて使われる想定です。

/Handlers/Account/AccountHandler.cs
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します。また、ユーザー作成時のオプションプロパティーを設定しています。

/Startup.cs
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を追加します。

/Controllers/AccountController.cs
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から新しいアカウントを作成してみましょう。

まずは正常系のリクエスト・レスポンスを試してみます。

正常リクエスト

image.png

正常レスポンス

image.png

DBの中身確認

DBの中身を確認すると新しいユーザーが生成されていることを確認しました。
image.png

異常系リクエスト

では異常系リクエストを試してみます。

image.png

異常系レスポンス

パスワードは少なくても6文字、3文字ユニークでないといけないとのことです。

image.png

アカウントが作成できたので、次はログインとトークンを発行してみましょう。

次回:ASP.NET Core 2 API x Identity でユーザー登録とアクセスを管理(JWT) 2. 基本メソッド編 (ログイン)

syantien
トランスコスモス技術研究所にて様々な開発案件を進めています。最近はKotlin頑張ってます。開発メンバー絶賛採用中。このどれかのキーワードでビビっと来た人は面談にお越しください。「ASP.NET C#」, 「Kotlin」,「Swift」,「Angular」,「QA」,「UXデザイナー」,「データサイエンティスト」,「海外開発案件挑戦してみたい」,「Shopify」。
http://syantien.hatenablog.com/
trnd
ソフトウェア・ウェブサービス開発時に読み返せる記事をまとめています。
https://t-rnd.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away