2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

タスク管理ツールをReact + ASP.Coreで作る 016サーバーサイドに認証機能を追加する

Last updated at Posted at 2022-11-05

前回の続きです

今回から数回に分けて認証機能を導入します

ガイド

全体Index:タスク管理ツールをReact + ASP.Coreで作る - Index

認証機能追加の一連の流れ

構築

本記事で実施する内容のサマリー

  • パッケージをインストール
  • 認証機能にかかわるコードを追加
    • ユーザーを管理のためのテーブルの原資になるクラスを追加
    • DBに認証ユーザーを管理するテーブルを追加する様に、コンテキストを変更
    • 認証関連操作(ログイン・新規登録・認証情報からログイン中のユーザー情報取得)のためのデータモデルを追加
    • 認証関連操作の為のコントローラークラスの追加
    • webサービス機能の中に認証機能を追加
  • マイグレーションしてデータベースを更新

パッケージをインストール

認証機能を有効にするため、以下のパッケージをNugetギャラリーからインストールします

  • 認証機能関連
    • Microsoft.AspNetCore.Authentication.JwtBearer
    • Microsoft.AspNetCore.Identity.UI

コード追加・変更

準備ができたら認証関連のコードを追加していきます。
以下のファイルを追加or変更します

ファイル名 変更内容 概要
ApplicationUser.cs 新規追加 ユーザー管理テーブル用モデルクラスを新規追加
DataContext.cs 変更 コンテキストクラスを認証機能付きに変更
AccountController.cs 新規追加 ログイン・ユーザー登録処理・結果取得を行うコントローラー
LoginModel.cs 新規追加 ログイン処理時にコントローラーにデータを渡すためのモデルクラス
RegisterModel.cs 新規追加 ユーザー登録時にコントローラーにデータを渡すためのモデルクラス
UserModel.cs 新規追加 ログイン・ユーザー登録後にコントローラーから結果を返す際に使用するクラス
Startup.cs 変更 認証関連の処理を追加する

ApplicationUser.cs

ApplicationUser.cs
using Microsoft.AspNetCore.Identity;

namespace server_app.Models.EDM
{
    public class ApplicationUser : IdentityUser
    {
    }
}

DataContext.cs

DataContext.cs

+ using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace server_app.Models.EDM
{
+   public class DataContext : IdentityDbContext<ApplicationUser>
    {
+       public DataContext(DbContextOptions<DataContext> options) : base(options)
        {
        }

        public DbSet<t_task> t_tasks {get; set;}
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
+           base.OnModelCreating(modelBuilder);
            
            modelBuilder.Entity<t_task>(entity =>
            {
                entity.HasKey(e => new { e.id_task });

            });
        }
    }
}

AccountController.cs

AccountController.cs
using System.Security.Claims;
using System.Threading.Tasks;
using server_app.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using server_app.Models.EDM;
using server_app.Models.DTO;

namespace server_app.Controllers
{
    [AllowAnonymous]
    [ApiController]
    [Route("[controller]")]
    public class AccountController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly  SignInManager<ApplicationUser> _signinManager;
        public AccountController(UserManager<ApplicationUser> userManager
            ,SignInManager<ApplicationUser> signinManager
             )
        {
            _signinManager = signinManager;
            _userManager = userManager;
        }

        [HttpPost("login")]
        public async Task<ActionResult<UserModel>> Login(LoginModel loginModel)
        {
            
            var user = await _userManager.FindByEmailAsync(loginModel.Email);

            if(user == null) return Unauthorized();

            var result = await _signinManager.CheckPasswordSignInAsync(user, loginModel.Password, false);

            if(result.Succeeded)
            {
                return CreateUserObject(user);
            }

            return Unauthorized();
        }

        [HttpPost("register")]
        public async Task<ActionResult<UserModel>> Register(RegisterModel registerModel)
        {
            if(await _userManager.Users.AnyAsync(x => x.Email == registerModel.Email))
            {
                ModelState.AddModelError("email", "Email taken");
                return ValidationProblem();
            }
            if(await _userManager.Users.AnyAsync(x => x.UserName == registerModel.Username))
            {
                ModelState.AddModelError("username", "Username taken");
                return ValidationProblem();
            }

            var user = new ApplicationUser
            {
                Email = registerModel.Email,
                UserName = registerModel.Username
            };

            var result = await _userManager.CreateAsync(user, registerModel.Password);

            if(result.Succeeded)
            {
                return CreateUserObject(user);
            }

            return BadRequest("Problem regist User");
        }
        private UserModel CreateUserObject(ApplicationUser user)
        {
            return new UserModel
            {
                    Username = user.UserName
            };
        }
    }
}

LoginModel.cs

LoginModel.cs

namespace server_app.Models.DTO
{
    public class LoginModel
    {
        public string Email {get; set;}
        public string Password {get; set;}
        
    }
}

RegisterModel.cs

RegisterModel.cs


using System.ComponentModel.DataAnnotations;

namespace server_app.Models.DTO
{
    public class RegisterModel
    {
        [Required]
        [EmailAddress]
        public string Email { get; set;}
        [Required]
        [RegularExpression("(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{4,8}$", ErrorMessage ="Password must be complex")]
        public string Password {get; set; }
        [Required]
        public string Username { get; set; }

        
    }
}

UserModel.cs

UserModel.cs
namespace server_app.Models.DTO
{
    public class UserModel
    {
        public string Username {get; set; }
        
    }
}

Startup.cs

Startup.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
+ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using server_app.Models.EDM;

namespace server_app
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            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)
        {
            services.AddDbContext<DataContext>(opt =>
            {
             opt.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
            } );

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "server_app", Version = "v1" });
            });

+             services.AddDefaultIdentity<ApplicationUser>(
+                 options => {
+                                options.SignIn.RequireConfirmedAccount = false;
+                             }
+                 )
+                 .AddEntityFrameworkStores<DataContext>();
            
           services.AddCors(o => o.AddPolicy(MyAllowSpecificOrigins, builder =>
           {
               builder.AllowAnyOrigin()    // Allow CORS Recest from all Origin
                      .AllowAnyMethod()    // Allow All Http method
                      .AllowAnyHeader();   // Allow All request header
           }));
        }

        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "server_app v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCors(MyAllowSpecificOrigins);   // Add For CORS

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}


データベース更新

コードの追加が出来たので、データベースを生成します。
以下のコマンドを実行します

dotnet ef migrations add addIdentity
dotnet ef database update

image.png

動作

ここまでの流れで認証機能の基本部分を導入しました。
各APIに認証状態に沿ってアクセス制限を行う設定を入れていないので、この時点では動作させてもこれまでと動きに違いはないので、動作は省略します。

続きは次回です

TAG:V000-13-00

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?