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();
        }
    }

GitHup = https://github.com/muratozeee/ReCapProject