Политика авторизации в основном приложении asp.net не работает - PullRequest
0 голосов
/ 30 января 2019

У меня есть приложение, в котором вошедшие в систему пользователи должны просматривать, создавать, редактировать или удалять только своих клиентов.

Я пытался реализовать это с помощью политик и требований с ядром asp.net.Однако после добавления атрибута авторизации в моем контроллере я получаю сообщение об ошибке «Отказано в доступе».

Я создал отдельные политики для создания и редактирования клиентов.

Вот запуск.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.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using ProsperCRM.Models;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using ProsperCRM.Areas.Identity.Services;
using Microsoft.AspNetCore.Identity;

namespace ProsperCRM
{
    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.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            //services.AddDbContext<ProsperCRMContext>(options =>
            //options.UseSqlServer(Configuration.GetConnectionString("ProsperCRMContext")));

            services.AddDbContext<ProsperCRMContext>(options =>
                   options.UseSqlite("Data Source=ProsperCRM.db"));

            // add authorization - each user can view, edit and delete only their own customers. the admin can view, delete and edit all customers in addition to creating new user accounts.
            services.AddAuthorization(options =>
            {
                options.AddPolicy("CreateAndEditCustomers", policy => policy.Requirements.Add(new CustomerAuthorizationRequirement()));
            });

            services.AddAuthorization(options =>
            {
                options.AddPolicy("CreateCustomers", policy => policy.Requirements.Add(new CustomerCreationRequirement()));
            });

            services.AddAuthorization(options =>
            {
                options.AddPolicy("CreateNewUsers", policy => policy.RequireRole("Admin"));
            });

        }

        // 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.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Вот одно из требований со свойством UserId:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using ProsperCRM.Areas.Identity.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ProsperCRM.Areas.Identity.Services
{
    public class CustomerAuthorizationRequirement : IAuthorizationRequirement
    {
        public string UserId { get; set; }

        public CustomerAuthorizationRequirement()
        {

        }

    }
}

Вот обработчик требования:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using ProsperCRM.Models;

namespace ProsperCRM.Areas.Identity.Services
{
    public class CustomerAuthorizationHandler : AuthorizationHandler<CustomerAuthorizationRequirement, Customer>
    {
        private readonly UserManager<Data.ProsperCRMUser> _userManager;

        public CustomerAuthorizationHandler(UserManager<Data.ProsperCRMUser> userManager)
        {
            _userManager = userManager;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomerAuthorizationRequirement requirement, Customer resource)
        {
            // var userId = _userManager.GetUserId(context.User);
            requirement.UserId = _userManager.GetUserId(context.User);
            if (resource.ApplicationUserId == requirement.UserId)
            {
                context.Succeed(requirement);
            }
            return Task.CompletedTask;
        }
    }
}

И, наконец,, контроллер клиентов, куда я добавляю атрибуты:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using ProsperCRM.Areas.Identity.Data;
using ProsperCRM.Areas.Identity.Services;
using ProsperCRM.Models;
using SendGrid;
using SendGrid.Helpers.Mail;

namespace ProsperCRM.Controllers
{

    public class CustomersController : Controller
    {
        private readonly ProsperCRMContext _context;
        private readonly IConfiguration _configuration;

        public CustomersController(ProsperCRMContext context, IConfiguration configuration)
        {
            _context = context;
            _configuration = configuration;
        }

        // GET: Customers
        [Authorize]
        // [Authorize(Policy = "CreateAndEditCustomers")]
        public async Task<IActionResult> Index()
        {

            CustomerViewModel model = new CustomerViewModel();

            // only customers for logged in user
            var list = await _context.Customer.ToListAsync();

            // customers for all users
            // var list = await _context.Customer.ToListAsync();

            model.Customers = list;

            return View(model);

        }

        [Authorize(Policy = "CreateAndEditCustomers")]
        // GET: Customers/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var customer = await _context.Customer
                .FirstOrDefaultAsync(m => m.ID == id);
            if (customer == null)
            {
                return NotFound();
            }

            return View(customer);
        }

        // GET: Customers/Create
        [Authorize]
        public IActionResult Create()
        {
            return View();
        }

        // POST: Customers/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        [Authorize(Policy = "CreateCustomers")]
        public async Task<IActionResult> Create([Bind("ID,FirstName,LastName,PhoneNumber,Email")] Customer customer)
        {
            if (ModelState.IsValid)
            {
                // customer.ApplicationUserId = _userManager.GetUserId(User);
                _context.Add(customer);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(customer);
        }

        // GET: Customers/Edit/5
        [Authorize(Policy = "CreateAndEditCustomers")]
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var customer = await _context.Customer.FindAsync(id);

            if (customer == null)
            {
                return NotFound();
            }

            /* old approach
            // User can only edit their entries
            var userId = _userManager.GetUserId(User);

            if (customer.ApplicationUserId != userId)
            {
                return NotFound();
            }
            */

            return View(customer);
        }

        // POST: Customers/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        [Authorize(Policy = "CreateAndEditCustomers")]
        public async Task<IActionResult> Edit(int id, [Bind("ID,FirstName,LastName,PhoneNumber,Email")] Customer customer)
        {
            if (id != customer.ID)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(customer);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!CustomerExists(customer.ID))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(customer);
        }

        // GET: Customers/Delete/5
        [Authorize(Policy = "CreateAndEditCustomers")]
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var customer = await _context.Customer
                .FirstOrDefaultAsync(m => m.ID == id);
            if (customer == null)
            {
                return NotFound();
            }

            return View(customer);
        }

        // POST: Customers/Delete/5
        [Authorize(Policy = "CreateAndEditCustomers")]
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var customer = await _context.Customer.FindAsync(id);

            _context.Customer.Remove(customer);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool CustomerExists(int id)
        {
            return _context.Customer.Any(e => e.ID == id);
        }

        [HttpPost]
        public IActionResult SendEmail(CustomerViewModel model)
        {
            // why returning notfound?
            if (model.SelectedCustomers == null)
            {
                return NotFound();
            }

            List<EmailAddressViewModel> nameAndEmail = new List<EmailAddressViewModel>();

            var customers = model.SelectedCustomers;

            for (var i = 0; i < customers.Count; i++)

            {
                if (customers[i].IsSelected)
                {
                    nameAndEmail.Add( new EmailAddressViewModel { Email = model.Customers[i].Email, Name = model.Customers[i].LastName }  );
                }
            }

            SendGridViewModel sendModel = new SendGridViewModel();

            sendModel.To = nameAndEmail;

            // ViewBag.Data = nameAndEmail;

            return View(sendModel);
        }

        [HttpPost]
        public async Task<IActionResult> SubmitEmail(SendGridViewModel model)
        {
            var tos = new List<EmailAddress>();

            var apiKey = _configuration.GetSection("SENDGRID_API_KEY").Value;
            var client = new SendGridClient(apiKey);
            var from = new EmailAddress("subs22222@gmail.com", "Example User");
            var subject = model.Subject;
            for (int i = 0; i < model.To.Count; i++)
            {
                tos.Add(new EmailAddress(model.To[i].Email, model.To[i].Name));
            }
            // var to = new EmailAddress("star113@gmail.com", "Example User");
            var plainTextContent = model.PlainTextContent;
            var htmlContent = "<strong>" + model.PlainTextContent + "</strong>";
            var msg = MailHelper.CreateSingleEmailToMultipleRecipients(from, tos, subject, plainTextContent, htmlContent);
            var response = await client.SendEmailAsync(msg);

            return RedirectToAction(nameof(Index));
        }
    }
}

Любая помощь будет принята с благодарностью.

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