Asp. Net Основные пользовательские модели, полученные из ApplicationUser. - PullRequest
0 голосов
/ 19 января 2020

Мы только начали изучать кодирование и работаем над проектом Asp. Net Core 3.1 Я знаю, что это простая проблема, но я искал везде и не нашел решения.

У нас есть пользовательские модели Admin, Client, Mentor, в которых есть все дополнительные реквизиты, которые нам нужны от пользователя, кроме стандартной электронной почты, Pass, First, Last Name, которые взяты из модели ApplicationUser.

поэтому у нас есть что-то вроде этого (вы можете найти ниже модели):

AdminUserDetails   ---\
ClientUserDetails  ------ : ApplicationUser : IdentityUser
MentorUserDetails  ---/

На данный момент аутентификация и авторизация работает правильно, но все пользователи создаются в таблице AspNetUser в EF, но мы хотим, чтобы каждая роль (например, клиент) создавалась в таблице клиента со всеми свойствами из ApplicationUser и IdentityUser, унаследованными.

Прежде всего, я нашел эту ссылку для наследования моделей от ApplicationUser. Это правильный способ сделать это?

Кроме того, когда пользователь регистрируется с ролью, выбранной в форме, мы хотим назначить этого пользователя соответствующей модели ... UserDetails и получить Identity Id в Guid.

Вот несколько примеров моделей:

public class ApplicationUser : IdentityUser
    {
        [Required]
        [MaxLength(50)]
        public string FirstName { get; set; }

        [Required]
        [MaxLength(50)]
        public string LastName { get; set; }

        [NotMapped]
        public string Name
        {
            get
            {
                return FirstName + " " + LastName;
            }
        }

        [Required]
        [Display(Name = "Phone Number")]
        [DataType(DataType.PhoneNumber)]
        public int? PhoneNumber { get; set; }

        [Display(Name = "Profile Picture")]
        [DataType(DataType.Upload)]
        public string? ProfilePicture { get; set; }
   }
public class AdministratorDetails : ApplicationUser
    {
        [Key]
        [ForeignKey("ApplicationUser")]
        public Guid Id { get; set; }

        //Προσθέτω Foreign key se ola ta details APP USER

        public virtual ApplicationUser ApplicationUser { get; set; }

    }

Запуск:

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.AddCors();
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));


            services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddRoles<IdentityRole>() //Πρόσθεσα Identity role
                .AddRoleManager<RoleManager<IdentityRole>>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

            services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
                    options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
                    options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
                })
                .AddIdentityServerJwt();


            services.AddControllersWithViews();
            services.AddRazorPages();

            // In production, the React files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/build";
            });

            //SendGrid Confirmation Email Sender
            services.AddTransient<IEmailSender, EmailSender>();
            services.Configure<AuthMessageSenderOptions>(Configuration);

            services.AddTransient<IProfileService, IdentityClaimsProfileService>();
            services.AddScoped<IJobCategoriesRepository, JobCategoryRepository>();
            services.AddScoped<IMentorRepository, MentorRepository>();
            services.AddScoped<IHrDetailsRepository, HrDetailsRepository>();
            services.AddScoped<IClientRepository, ClientRepository>();
            services.AddScoped<IJobListingsRepository, JobListingsRepository>();
            services.AddScoped<IMentorOfferRepository, MentorOfferRepository>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }


            app.UseCors(
                options => options.WithOrigins("https://localhost:5001/")
                                  .AllowAnyHeader()
                                  .AllowAnyMethod()
            );

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseSpaStaticFiles();

            app.UseRouting();

            app.UseIdentityServer();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseReactDevelopmentServer(npmScript: "start");
                }
            });


            app.UseStaticFiles();

            app.UseIdentityServer();

            CreateRoles(serviceProvider).Wait();
        }


        private async Task CreateRoles(IServiceProvider serviceProvider)
        {
            //adding custom roles
            var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
            var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
            string[] roleNames = { "Admin", "HR", "Mentor", "Client" };
            IdentityResult roleResult;

            foreach (var roleName in roleNames)
            {
                //creating the roles and seeding them to the database
                var roleExist = await RoleManager.RoleExistsAsync(roleName);
                if (!roleExist)
                {
                    roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
                }
            }


            //creating a super user who could maintain the web app

            var powerUser = new ApplicationUser
            {
                UserName = Configuration.GetSection("UserSettings")["UserEmail"],
                Email = Configuration.GetSection("UserSettings")["UserEmail"],

                FirstName = "PowerAdmin",
                LastName = "Admin",
                UserRole = "Admin",
                EmailConfirmed = true
            };


            string UserPassword = Configuration.GetSection("UserSettings")["UserPassword"];
            var _user = await UserManager.FindByEmailAsync(Configuration.GetSection("UserSettings")["UserEmail"]);

            if (_user == null)
            {
                var createPowerUser = await UserManager.CreateAsync(powerUser, UserPassword);
                if (createPowerUser.Succeeded)
                {
                    //here we tie the new user to the "Admin" role 
                    await UserManager.AddToRoleAsync(powerUser, "Admin");

                }

            }

        }

        public class IdentityClaimsProfileService : IProfileService
        {
            private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
            private readonly UserManager<ApplicationUser> _userManager;

            public IdentityClaimsProfileService(UserManager<ApplicationUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory)
            {
                _userManager = userManager;
                _claimsFactory = claimsFactory;
            }

            public async Task GetProfileDataAsync(ProfileDataRequestContext context)
            {
                var sub = context.Subject.GetSubjectId();
                var user = await _userManager.FindByIdAsync(sub);
                var principal = await _claimsFactory.CreateAsync(user);
                var roles = await _userManager.GetRolesAsync(user);
                var claims = principal.Claims.ToList();
                claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
                foreach(string role in roles)
                {
                    claims.Add(new Claim(JwtClaimTypes.Role, role));
                }

                context.IssuedClaims = claims;
            }

            public async Task IsActiveAsync(IsActiveContext context)
            {
                var sub = context.Subject.GetSubjectId();
                var user = await _userManager.FindByIdAsync(sub);
                context.IsActive = user != null;
            }
        }

1 Ответ

0 голосов
/ 22 января 2020

Благодаря @Xin Zou в комментариях я наконец понял, что мне нужно удалить наследство IdentityUser из моих моделей Users и установить только внешний ключ для каждого пользователя

 [ForeignKey("ApplicationUserId")]
 public ApplicationUser ApplicationUser { get; set; }
 public string ApplicationUserId { get; set; }

Таким образом, создав таблицу AspNetUser, но также Таблица пользователей (в соответствии с ее ролью) с внешним ключом AspNetUser. Единственная проблема здесь заключается в том, что пользовательские таблицы должны иметь свои пропускаемые значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...