08.06.2023
Моя цель — изучить C# и поделиться своими знаниями с людьми. Я упомянул примеры с кодами комментариев.
Мы продолжим RentCarProject(ReCapProject)
Требования:
- Сделайте интеграцию JWT.
Теперь мы добавим возможность JWT (Json Web Token) в проект RentCar. И мы будем контролировать с помощью аспектов. Мы не будем размещать авторизацию на уровне WebAPI. Потому что, возможно, изменится API. Вот почему мы создадим базу, и это будет устойчивая система. В этом случае эту авторизацию можно использовать с приложением Deskop, Wep, Mobil и т. Д.
Процесс авторизации в Cross Cutting Concern…
Общие опасения
В C# сквозные проблемы относятся к аспектам программного приложения, которые влияют на несколько частей системы и не могут быть легко отделены от них. Некоторые примеры сквозных проблем в C# включают регистрацию, кэширование, безопасность и обработку ошибок.
C# предлагает несколько механизмов для управления сквозными задачами, включая наследование, интерфейсы и атрибуты. Например, вы можете создать базовый класс, обеспечивающий ведение журнала, и наследовать от него другие классы, чтобы наследовать эти функции. В качестве альтернативы вы можете определить интерфейсы, которые определяют поведение, необходимое для сквозных задач, и реализовать классы для реализации этих интерфейсов, чтобы гарантировать, что они обеспечивают требуемую функциональность.
Другим распространенным подходом к управлению сквозными задачами в C# является использование сред аспектно-ориентированного программирования (АОП), таких как PostSharp, Castle Windsor или Unity. Эти платформы позволяют вам определять аспекты, которые инкапсулируют сквозные проблемы, а затем применять их к определенным частям кодовой базы, используя атрибуты или другие механизмы. Это может упростить управление этими проблемами и уменьшить дублирование кода.
Давайте начнем
[SecuredOperation("admin,editor")]
Это означает, что мы использовали Аспект для использования авторизации, и администратор или редактор могут контролировать управление пользователями или что-то еще, что мы добавим для этой операции. И также эта операция может быть изменена так, как нам нужно…
(админ, редактор) это ключ какие они.
Мы называем претензию…
Claim=это означает, что (администратор или редактор) может предъявлять претензии…
Претензия=(админ,редактор)
JWT (веб-токен Json)
Можно сказать, что клиент - это веб, мобильное приложение, настольное приложение.
Например, Google Chrome является клиентом.
Мы запрашиваем что-то из API, тогда авторизация может быть связана друг с другом. Если это правильно, или админ, или данные, и т. Д., Мы можем выполнять операции.
Например = у нас есть пароль и gmail, затем мы запрашиваем токен из API.
Затем, если это правильно, он передаст веб-токен json клиенту. И клиент будет хранить память, базу данных или что-то еще, в зависимости от системы, это может быть что угодно. Затем клиент все запрашивает с помощью http-письма, а также у меня есть авторизация JWT, тогда мы можем подключиться к базе данных или чему-то еще, потому что у меня есть ключ (JWT). тогда мы можем делать все в зависимости от авторизации.
формат JSON
Json= В C# JSON (нотация объектов JavaScript) — это упрощенный формат обмена данными, который широко используется для веб-связи между клиентскими и серверными приложениями. JSON — это текстовый формат, состоящий из пар ключ-значение, где ключи — это строки, а значения могут быть строками, числами, логическими значениями, массивами или объектами.
Хеширование
В C# хеширование — это процесс преобразования заданных входных данных (например, строки или массива байтов) в значение фиксированного размера, обычно числовое значение или строку символов. с помощью хеш-функции. Результирующее значение, также известное как хеш-код или просто хэш, обычно намного меньше, чем входное значение, и может использоваться в качестве уникального идентификатора или для проверки целостности входного значения.
C# предоставляет несколько встроенных хэш-функций, таких как MD5, SHA-1, SHA-256, SHA-384 и SHA-512, которые можно использовать для вычисления хэш-функции заданного ввода. Например, для вычисления хэша SHA-256 строкового ввода.
Пример хеширования = мы делаем пароль 123@123. И алгоритмы хеширования работают с такими алгоритмами, как MD5, SHA-1, SHA-256, SHA-384 и SHA-512,
В базе данных 123@123 = BDX3–5fgsdg-ghgkdf мы держим вот так. Это не может вернуться раньше значения.then
Мы проверяем 123@12, мы входим в систему, затем пароль хэширует их и проверяет друг друга. После этого мы видим, что между 123@123 и 123@12 не то же самое.
когда кто-то достигает базы данных и не может использовать пароли. Но кто-то использует радужную таблицу. Это означает, что используется алгоритм расшифровки sha-1 и перехватывает пароль. Нам это не нужно. Вот почему мы используем метод Salting, это означает, что он может добавить .@_-abc12 этот хеш-пароль не может быть найден, он будет найден очень долго (приблизительно 10 лет 😊), чтобы найти пароль .что мы сделали. Двойная безопасность..!
Шифрование= он может вернуть пароль, когда пароль зашифрован с помощью расшифровки.
Шифрование
Шифрование — это процесс преобразования открытого текста (незашифрованных данных) в зашифрованный текст (зашифрованные данные) с использованием алгоритма шифрования и ключа. Полученный зашифрованный текст неразборчив без ключа и может быть расшифрован обратно в открытый текст только тем, у кого есть доступ к ключу.
В C# существует несколько алгоритмов шифрования, которые можно использовать для шифрования данных, например AES, DES и RSA. .NET Framework предоставляет набор классов в пространстве имен System.Security.Cryptography
, которые реализуют эти алгоритмы и другие связанные функции.
Расшифровка
В C# под дешифрованием понимается процесс преобразования зашифрованных данных обратно в исходную удобочитаемую форму. В C# доступно несколько криптографических алгоритмов и библиотек, которые можно использовать для расшифровки. Вот пример того, как вы можете выполнить расшифровку с использованием алгоритма AES (Advanced Encryption Standard).
Делаем в Project.
Прежде чем мы создали таблицу пользователей в PostgreSql, мы обновили ее с помощью хэша…,
Затем давайте создадим VS и подключимся к базе данных…
Мы будем использовать весь проект, он не изменится, поэтому мы можем создать базовый слой в классе сущностей… Давайте посмотрим
Создан пользователь на основном уровне в файле сущностей.
public class User : IEntity { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public byte[] PasswordSalt { get; set; } public byte[] PasswordHash { get; set; } public bool Status { get; set; } }
Созданные свойства в VS
public class OperationClaim : IEntity { public int Id { get; set; } public string Name { get; set; } } public class UserOperationClaim : IEntity { public int Id { get; set; } public int UserId { get; set; } public int OperationClaimId { get; set; } }
Созданные объекты из базы данных
Appsettings.json = мы можем настроить API в настройках. Мы можем поместить туда строки подключения, также мы будем использовать там конфигурацию Jwt.
Jwt имеет поле, и мы должны их поместить.
{ //tokenOptions it is one of them in fields. "TokenOptions": { //it has to have Audience in jwt "Audience": "[email protected]", //issuer it means execute like that. "Issuer": "[email protected]", //it can work time.we are puting minute we put there 10 minutes "AccessTokenExpiration": 10, //it is ket when we are using ASP.Net "SecurityKey": "mysupersecretkeymysupersecretkey" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Напишем посредник для хеширования
public class HashingHelper { //we created passwordHash //also it will create the salt //out= we are giving out the reference //taking password and we are giving out passwordHash and out passwordSalt public static void CreatePasswordHash(string password,out byte[] passwordHash,out byte[] passwordSalt) { //IDisposible pattern //hmac=crypto class //we are creating the cyrptograhy method using Sha512 algorithm using (var hmac = new System.Security.Cryptography.HMACSHA512()) { //we are giving out with hcmac.key //every each user has a different key. passwordSalt = hmac.Key; //we are giving hashing for password to out also we can not write just password //we have to take byte type but it is string that's why we have to encoding.UTF8.GetBytes(password) // then we can use it. passwordHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password)); } } //we verified passwordHash //we will not use out because we are taking here that's why no need it.we are using for verifypassword. //we will compare password(from user) and passwordhash(from database) to verify in here.Also salt we will execute it.- public static bool VerifyPasswordHash(string password,byte[] passwordHash,byte[] passwordSalt ) { //also we are using salt from here. using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt)) { //password is user password.User trying the password in the system and we will hash and we will compare them //to verify. var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password)); //we are checking form user password with database password to verify. if they are same, it will return false //if they are different, it will return true. for (int i = 0; i < computedHash.Length; i++) { if (computedHash[i]!= passwordHash[i]) { return false; } } } return true; } }
Создан SecurityKeyHelper
Мы изменили формат байтового массива для понимания системы на jwt.
Мы можем создать ключ со строкой. Мы изменили формат массива byte[].
Мы должны добавить это приложение в основной слой.
Добавлено это приложение в основной слой.
namespace Core.Utilities.Security.Encryption { public class SecurityKeyHelper { public static SecurityKey CreateSecurityKey(string securityKey) { //SymmetricSecurityKey=created the instance of securitykey return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey)); } } }
namespace Core.Utilities.Security.Encryption { public class SigningCredentialsHelper { //JWT can create with credentials in WebAPI //Username and Password are credentials.. public static SigningCredentials CreateSigningCredentials(SecurityKey securityKey) { //Web API JWT is defined the which key and which algorithm will use in the system. return new SigningCredentials(securityKey,SecurityAlgorithms.HmacSha512Signature); } } }
Создан AccessToken
Мы будем использовать jwt для связи с API и приложением…
У него есть ключ. это бессмысленно
public class AccessToken { //it is token information public string Token { get; set; } //also it has time to expired we are giving time to access... public DateTime Expiration { get; set; } }
Создан ItokenHelper
namespace Core.Utilities.Security.JWT { public interface ITokenHelper { AccessToken CreateToken(User user, List<OperationClaim> operationClaims); } }
1)Ввел имя пользователя
2)Ввел пароль
3)Нажмите кнопку .
4) информация об имени пользователя и пароле API
5) проверив базу данных, он найдет претензии
6) создание jwt
7) и информация об успехе.
Сначала я напишу сплошные коды, а затем добавлю к ним комментарии. Также, когда мы пишем код, мы должны добавить какое-то приложение в vs.
public class JwtHelper : ITokenHelper { //IConfiguration can help read the appstettings.json public IConfiguration Configuration { get; } //when ı read from appsettings.json ı will send the object private TokenOptions _tokenOptions; //which time access token will be expiration... private DateTime _accessTokenExpiration; //we did the injection public JwtHelper(IConfiguration configuration) { Configuration = configuration; //it is matching the from API appsettings.json to TokenOptions fields you can check them... _tokenOptions = Configuration.GetSection("TokenOptions").Get<TokenOptions>(); } //it is creating the token for user... and give the claims then it will create the token depending on user and claims. public AccessToken CreateToken(User user, List<OperationClaim> operationClaims) { //it is taken expirationtime from appsetting.json to TokenOptions they will match each other as a same field. //it is added 10 min expiration time check the appsettings.json in WebAPI _accessTokenExpiration = DateTime.Now.AddMinutes(_tokenOptions.AccessTokenExpiration); //it is creating the securityKey from tokenoptions var securityKey = SecurityKeyHelper.CreateSecurityKey(_tokenOptions.SecurityKey); //which algorith will use in securityKey.then before SigningCredentialsHelper class created for //which algorithm will use when you check there.SHA-512 var signingCredentials = SigningCredentialsHelper.CreateSigningCredentials(securityKey); //we wrote the method it includes TokenOptions,user,signingCredentials,operationClaims(Authority) var jwt = CreateJwtSecurityToken(_tokenOptions, user, signingCredentials, operationClaims); var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); var token = jwtSecurityTokenHandler.WriteToken(jwt); return new AccessToken { Token = token, Expiration = _accessTokenExpiration }; } public JwtSecurityToken CreateJwtSecurityToken(TokenOptions tokenOptions, User user, SigningCredentials signingCredentials, List<OperationClaim> operationClaims) { //jwt is created JwtSecurityToken var jwt = new JwtSecurityToken( issuer: tokenOptions.Issuer, audience: tokenOptions.Audience, expires: _accessTokenExpiration, notBefore: DateTime.Now, claims: SetClaims(user, operationClaims), signingCredentials: signingCredentials ); //also all options is creating instance in jwt and return it. return jwt; } private IEnumerable<Claim> SetClaims(User user, List<OperationClaim> operationClaims) { var claims = new List<Claim>(); claims.AddNameIdentifier(user.Id.ToString()); claims.AddEmail(user.Email); claims.AddName($"{user.FirstName} {user.LastName}"); claims.AddRoles(operationClaims.Select(c => c.Name).ToArray()); return claims; } }
public class TokenOptions { public string Audience { get; set; } public string Issuer { get; set; } public int AccessTokenExpiration { get; set; } public string SecurityKey { get; set; } }
Загружено в основной слой.
Примечание = мы можем добавить методы для класса, мы можем сказать, что это означает (расширение)
public static class ClaimExtensions { //this ICollection<Claim> claims = when we see this code //there is no in here normal.it is coming from .Net directly we are just extension them. //normally we have everyeach one have to new them //but no need we can shortly use them with extension method as a claim public static void AddEmail(this ICollection<Claim> claims, string email) { claims.Add(new Claim(JwtRegisteredClaimNames.Email, email)); } public static void AddName(this ICollection<Claim> claims, string name) { claims.Add(new Claim(ClaimTypes.Name, name)); } public static void AddNameIdentifier(this ICollection<Claim> claims, string nameIdentifier) { claims.Add(new Claim(ClaimTypes.NameIdentifier, nameIdentifier)); } public static void AddRoles(this ICollection<Claim> claims, string[] roles) { roles.ToList().ForEach(role => claims.Add(new Claim(ClaimTypes.Role, role))); } }
public static class ClaimsPrincipalExtensions { //when we search the claim we have to write roles to find claim like that. //that's why we are extension them. //? =it can be null it means.why because sometimes claim is not created that's why it has to be null. public static List<string> Claims(this ClaimsPrincipal claimsPrincipal, string claimType) { var result = claimsPrincipal?.FindAll(claimType)?.Select(x => x.Value).ToList(); return result; } public static List<string> ClaimRoles(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal?.Claims(ClaimTypes.Role); } }
Затем мы добавили
с помощью Microsoft.Extensions.DependencyInjection;
в защищенных операциях.
//JWT is Http request and AOP public class SecuredOperation : MethodInterception { private string[] _roles; //when we request the jwt, it will be created Httpcontext private IHttpContextAccessor _httpContextAccessor; public SecuredOperation(string roles) { //Split is seperate firstly then sending the array. _roles = roles.Split(','); //ServiceTool we can read the infrastructure _httpContextAccessor = ServiceTool.ServiceProvider.GetService<IHttpContextAccessor>(); } protected override void OnBefore(IInvocation invocation) { var roleClaims = _httpContextAccessor.HttpContext.User.ClaimRoles(); foreach (var role in _roles) { if (roleClaims.Contains(role)) { return; } } throw new Exception(Messages.AuthorizationDenied); } }
Нам нужно загрузить пакеты в Solution и выбрать для уровня Business.
Затем мы добавили
public static class ServiceTool { //these code provide the creating injection from Autofac public static IServiceProvider ServiceProvider { get; private set; } public static IServiceCollection Create(IServiceCollection services) { ServiceProvider = services.BuildServiceProvider(); return services; } }
//it can use the Database public interface IUserDal : IEntityRepository<User> { List<OperationClaim> GetClaims(User user); }
Затем мы подключаемся к базе данных
public class EfUserDal : EfEntityRepositoryBase<User, CarContext>, IUserDal { public List<OperationClaim> GetClaims(User user) { using (var context = new CarContext()) { var result = from operationClaim in context.OperationClaims join userOperationClaim in context.UserOperationClaims on operationClaim.Id equals userOperationClaim.OperationClaimId where userOperationClaim.UserId == user.Id select new OperationClaim { Id = operationClaim.Id, Name = operationClaim.Name }; return result.ToList(); } } }
Также мы добавляем сущности jwt в CarContext.
public class CarContext:DbContext { //we are selecting the which database protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(@"Host = localhost; Username = postgres; Password = 1234; Database = RentCarDB; Pooling = true;"); //Connection String.. //for time enable to working with together time. AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); } //which object in sql server match which object in project we are doint it public DbSet<Car> Cars { get; set; } public DbSet<Brand> Brands { get; set; } public DbSet<Color> Colors { get; set; } public DbSet<Customer> Customers { get; set; } public DbSet<Rental> Rentals { get; set; } public DbSet<CarImage> CarImages { get; set; } public DbSet<OperationClaim> OperationClaims { get; set; } public DbSet<Core.Entities.Concrete.User> Users { get; set; } public DbSet<UserOperationClaim> UserOperationClaims { get; set; } }
public interface IAuthService { IDataResult<User> Register(UserForRegisterDto userForRegisterDto, string password); IDataResult<User> Login(UserForLoginDto userForLoginDto); IResult UserExists(string email); IDataResult<AccessToken> CreateAccessToken(User user); } public interface IUserService { List<OperationClaim> GetClaims(User user); void Add(User user); User GetByMail(string email); }
//they are common all thing that's why we are using together. public class UserForLoginDto : IDto { public string Email { get; set; } public string Password { get; set; } } public class UserForRegisterDto : IDto { public string Email { get; set; } public string Password { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
Рефакторинг UserManager
public class UserManager : IUserService { //UserDal is injected IUserDal _userDal; public UserManager(IUserDal userDal) { _userDal = userDal; } public List<OperationClaim> GetClaims(User user) { //taking claim with user. return _userDal.GetClaims(user); } //adding public void Add(User user) { _userDal.Add(user); } //getbyemail public User GetByMail(string email) { return _userDal.Get(u => u.Email == email); } }
Создан AuthManager
public class AuthManager : IAuthService { private IUserService _userService; private ITokenHelper _tokenHelper; public AuthManager(IUserService userService, ITokenHelper tokenHelper) { _userService = userService; _tokenHelper = tokenHelper; } public IDataResult<User> Register(UserForRegisterDto userForRegisterDto, string password) { byte[] passwordHash, passwordSalt; HashingHelper.CreatePasswordHash(password, out passwordHash, out passwordSalt); var user = new User { Email = userForRegisterDto.Email, FirstName = userForRegisterDto.FirstName, LastName = userForRegisterDto.LastName, PasswordHash = passwordHash, PasswordSalt = passwordSalt, Status = true }; _userService.Add(user); return new SuccessDataResult<User>(user, Messages.UserRegistered); } public IDataResult<User> Login(UserForLoginDto userForLoginDto) { var userToCheck = _userService.GetByMail(userForLoginDto.Email); if (userToCheck == null) { return new ErrorDataResult<User>(Messages.UserNotFound); } if (!HashingHelper.VerifyPasswordHash(userForLoginDto.Password, userToCheck.PasswordHash, userToCheck.PasswordSalt)) { return new ErrorDataResult<User>(Messages.PasswordError); } return new SuccessDataResult<User>(userToCheck, Messages.SuccessfulLogin); } public IResult UserExists(string email) { if (_userService.GetByMail(email) != null) { return new ErrorResult(Messages.UserAlreadyExists); } return new SuccessResult(); } public IDataResult<AccessToken> CreateAccessToken(User user) { var claims = _userService.GetClaims(user); var accessToken = _tokenHelper.CreateToken(user, claims); return new SuccessDataResult<AccessToken>(accessToken, Messages.AccessTokenCreated); } }
[Route("api/[controller]")] [ApiController] public class AuthController : Controller { private IAuthService _authService; public AuthController(IAuthService authService) { _authService = authService; } [HttpPost("login")] public ActionResult Login(UserForLoginDto userForLoginDto) { var userToLogin = _authService.Login(userForLoginDto); if (!userToLogin.Success) { return BadRequest(userToLogin.Message); } var result = _authService.CreateAccessToken(userToLogin.Data); if (result.Success) { return Ok(result.Data); } return BadRequest(result.Message); } [HttpPost("register")] public ActionResult Register(UserForRegisterDto userForRegisterDto) { var userExists = _authService.UserExists(userForRegisterDto.Email); if (!userExists.Success) { return BadRequest(userExists.Message); } var registerResult = _authService.Register(userForRegisterDto, userForRegisterDto.Password); var result = _authService.CreateAccessToken(registerResult.Data); if (result.Success) { return Ok(result.Data); } return BadRequest(result.Message); } }
Также переработан AutofacBusinessModule для создания экземпляра в бэкэнде.
public class AutofacBusinessModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<CarManager>().As<ICarService>().SingleInstance(); builder.RegisterType<EfCarDal>().As<ICarDal>().SingleInstance(); builder.RegisterType<BrandManager>().As<IBrandService>().SingleInstance(); builder.RegisterType<EfBrandDal>().As<IBrandDal>().SingleInstance(); builder.RegisterType<ColorManager>().As<IColorService>().SingleInstance(); builder.RegisterType<EfColorDal>().As<IColorDal>().SingleInstance(); builder.RegisterType<CustomerManager>().As<ICustomerService>().SingleInstance(); builder.RegisterType<EfCustomerDal>().As<ICustomerDal>().SingleInstance(); builder.RegisterType<RentalManager>().As<IRentalService>().SingleInstance(); builder.RegisterType<EfRentalDal>().As<IRentalDal>().SingleInstance(); builder.RegisterType<UserManager>().As<IUserService>().SingleInstance(); builder.RegisterType<EfUserDal>().As<IUserDal>().SingleInstance(); builder.RegisterType<CarImageManager>().As<ICarImageService>().SingleInstance(); builder.RegisterType<EfCarImageDal>().As<ICarImageDal>().SingleInstance(); builder.RegisterType<FileHelperManager>().As<IFileHelperService>().SingleInstance(); builder.RegisterType<UserManager>().As<IUserService>(); builder.RegisterType<EfUserDal>().As<IUserDal>(); builder.RegisterType<AuthManager>().As<IAuthService>(); builder.RegisterType<JwtHelper>().As<ITokenHelper>(); var assembly = System.Reflection.Assembly.GetExecutingAssembly(); builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces() .EnableInterfaceInterceptors(new ProxyGenerationOptions() { Selector = new AspectInterceptorSelector() }).SingleInstance(); } }
Рефакторинг program.cs в WebAPI
public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // it means new and just one reference for that one and it is provide us very fast no need to memory every each one... //builder.Services.AddSingleton<IBrandService, BrandManager>(); //builder.Services.AddSingleton<IBrandDal, EfBrandDal>(); //builder.Services.AddSingleton<ICarService, CarManager>(); //builder.Services.AddSingleton<ICarDal, EfCarDal>(); //builder.Services.AddSingleton<IColorService, ColorManager>(); //builder.Services.AddSingleton<IColorDal, EfColorDal>(); //builder.Services.AddSingleton<ICustomerService, CustomerManager>(); //builder.Services.AddSingleton<ICustomerDal, EfCustomerDal>(); //builder.Services.AddSingleton<IRentalService, RentalManager>(); //builder.Services.AddSingleton<IRentalDal, EfRentalDal>(); //builder.Services.AddSingleton<IUserService ,UserManager>(); //builder.Services.AddSingleton<IUserDal, EfUserDal>(); var tokenOptions = Configuration.GetSection("TokenOptions").Get<TokenOptions>(); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidIssuer = tokenOptions.Issuer, ValidAudience = tokenOptions.Audience, ValidateIssuerSigningKey = true, IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey) }; }); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); //Autofac builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); builder.Host.ConfigureContainer<ContainerBuilder>(options => { options.RegisterModule(new AutofacBusinessModule()); }); // var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); //it is middlewave app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); } }