如何将包含UserManager <ApplicationUser>的services.AddSingleton添加到启动类

如何解决如何将包含UserManager <ApplicationUser>的services.AddSingleton添加到启动类

添加服务时出现错误。启动类中的AddSingleton。

它一直起作用,直到我尝试添加UserManager位。我不知道用Usermanager实例化类的语法。

我正在关注this code,但是我需要使用.netCore身份来管理用户,而他正在使用简单的字典。

我得到的错误是:

InvalidOperationException:无法解析作用域服务 'Microsoft.AspNetCore.Identity.UserManager`1 [ibasis_api.Areas.Identity.Data.ibasis_apiUser]' 来自根提供商。

我怀疑错误的行是:

 services.AddSingleton<IJWTAuthenticationManager>(x =>
                    new JWTAuthenticationManager(tokenKey,x.GetService<IRefreshTokenGenerator>(),x.GetService<UserManager<ibasis_apiUser>>()
                ));

启动:

  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<ibasisLiveDbContext>(options =>
          options.UseSqlServer(
           Configuration.GetConnectionString("DefaultConnection")
           ));

        services.AddDbContext<IdentityContext>(options =>
            options.UseSqlServer(
        Configuration.GetConnectionString("ibasis_apiAuthContextConnection")
        ));
        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
        var appSettings = appSettingsSection.Get<AppSettings>();
        var tokenKey = appSettings.Secret;
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);

        var builder = services.AddIdentityCore<ibasis_apiUser>(o =>
        {
            // configure identity options
            o.Password.RequireDigit = false;
            o.Password.RequireLowercase = false;
            o.Password.RequireUppercase = false;
            o.Password.RequireNonAlphanumeric = false;
            o.Password.RequiredLength = 6;
            o.Lockout.MaxFailedAccessAttempts = 10;
            o.User.RequireUniqueEmail = false;
            o.SignIn.RequireConfirmedEmail = false;

        }).AddRoles<IdentityRole>();

        services.AddIdentity<ibasis_apiUser,IdentityRole>()
       
        .AddEntityFrameworkStores<IdentityContext>()
        .AddDefaultTokenProviders();

        IdentityModelEventSource.ShowPII = true;
        

        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(key),ValidateIssuer = false,ValidateAudience = false,ValidateLifetime = true,ClockSkew = TimeSpan.Zero,};
            });

       

        services.AddControllers();

        services.AddSwaggerGen(setup =>
        {
            setup.SwaggerDoc(
                "V1",new OpenApiInfo
                {
                    Title = "iBais API",Version = "v1"
                }
                );
        });


        //var userManager = (UserManager<ibasis_apiUser>)Scope.ServiceProvider.GetService(typeof(UserManager<ibasis_apiUser>));
        //UserManager<ibasis_apiUser> userManager =serviceProvider.GetRequiredService<UserManager<ibasis_apiUser>>();
        //UserManager<ibasis_apiUser> userManager = new UserManager<ibasis_apiUser>(); services.G serviceProvider.GetRequiredService<UserManager<ibasis_apiUser>>();


        services.AddSingleton<ITokenRefresher>(x =>
                new TokenRefresher(key,x.GetService<IJWTAuthenticationManager>(),x.GetService<UserManager<ibasis_apiUser>>() //Suspect Line
                ));

        services.AddSingleton<IRefreshTokenGenerator,RefreshTokenGenerator>();

        services.AddSingleton<IJWTAuthenticationManager>(x =>
                new JWTAuthenticationManager(tokenKey,x.GetService<UserManager<ibasis_apiUser>>()//Suspect Line
            ));
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app,IWebHostEnvironment env,ILoggerFactory loggerFactory)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

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

        app.UseSwagger();
        app.UseSwaggerUI(x =>
        {
            x.SwaggerEndpoint("/swagger/v1/swagger.json","iBasis API v1");
            //x.RoutePrefix = string.Empty;
        });
        loggerFactory.AddFile(Configuration.GetSection("Logging"));
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

JWTAuthenticationManager界面

 public interface IJWTAuthenticationManager
{
    Task<AuthenticationResponse> Authenticate(string username,string password);
    Task<AuthenticationResponse> Authenticate(string username,Claim[] claims);
}

JWTAuthenticationManager

public class JWTAuthenticationManager : IJWTAuthenticationManager
{
   

    private readonly string tokenKey;
    private readonly IRefreshTokenGenerator refreshTokenGenerator;
    private readonly UserManager<ibasis_apiUser> _userManager;

    public JWTAuthenticationManager(string tokenKey,IRefreshTokenGenerator refreshTokenGenerator,UserManager<ibasis_apiUser> usermanager)
    {
        this.tokenKey = tokenKey;
        this.refreshTokenGenerator = refreshTokenGenerator;
        _userManager = usermanager;
    }


    public async Task<AuthenticationResponse> Authenticate(string username,Claim[] claims)
    {
        var token = GenerateTokenString(username,DateTime.UtcNow,claims);
        var refreshToken = refreshTokenGenerator.GenerateToken();

        var user = await _userManager.FindByNameAsync(username);
        user.RefreshTokens = refreshToken;
        await _userManager.UpdateAsync(user);

        return new AuthenticationResponse
        {
            JwtToken = token,RefreshToken = refreshToken
        };
    }


    public async Task<AuthenticationResponse> Authenticate(string username,string password)
    {
        var user = await _userManager.FindByNameAsync(username);

        if(user != null && !await _userManager.CheckPasswordAsync(user,password))
        {
            return null;
        }

        var token = GenerateTokenString(username,DateTime.UtcNow);
        var refreshToken = refreshTokenGenerator.GenerateToken();

        //Save Token
        user.RefreshTokens = refreshToken;
        await _userManager.UpdateAsync(user);

        return new AuthenticationResponse
        {
            JwtToken = token,RefreshToken = refreshToken
        };
    }

    string GenerateTokenString(string username,DateTime expires,Claim[] claims = null)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(tokenKey);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(
             claims ?? new Claim[]
            {
                new Claim(ClaimTypes.Name,username)
            }),//NotBefore = expires,Expires = expires.AddMinutes(2),SigningCredentials = new SigningCredentials(
                new SymmetricSecurityKey(key),SecurityAlgorithms.HmacSha256Signature)
        };

        return tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor));
    }

    private async Task<bool> IsValidUsernameAndPassowrd(string username,string password)
    {
        var user = await _userManager.FindByNameAsync(username);
        return await _userManager.CheckPasswordAsync(user,password);

    }
}

TokenRefresher

 public class TokenRefresher : ITokenRefresher
{
    private readonly byte[] key;
    private readonly IJWTAuthenticationManager jWTAuthenticationManager;
    private readonly UserManager<ibasis_apiUser> _userManager;

    public TokenRefresher(byte[] key,IJWTAuthenticationManager jWTAuthenticationManager,UserManager<ibasis_apiUser> usermanager)
    {
        this.key = key;
        this.jWTAuthenticationManager = jWTAuthenticationManager;
        _userManager = usermanager;
    }

    public async Task<AuthenticationResponse> Refresh(RefreshCred refreshCred)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        SecurityToken validatedToken;
        var pricipal = tokenHandler.ValidateToken(refreshCred.JwtToken,new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,ValidateLifetime = false //here we are saying that we don't care about the token's expiration date
            },out validatedToken);
        var jwtToken = validatedToken as JwtSecurityToken;
        if (jwtToken == null || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256,StringComparison.InvariantCultureIgnoreCase))
        {
            throw new SecurityTokenException("Invalid token passed!");
        }

        var userName = pricipal.Identity.Name;
        var user = await _userManager.FindByNameAsync(userName);

        if (refreshCred.RefreshToken != user.RefreshTokens)
        {
            throw new SecurityTokenException("Invalid token passed!");
        }

        return  await jWTAuthenticationManager.Authenticate(userName,pricipal.Claims.ToArray());
    }

    
}

解决方法

因此,我用一些代码示例扩展了我的评论

首先,考虑将IJWTAuthenticationManager注册为范围服务:

services.AddScoped<IJWTAuthenticationManager>(serviceProvider =>
    ActivatorUtilities.CreateInstance<JWTAuthenticationManager>(serviceProvider,tokenKey));

您可以使用ActivatorUtilities类将tokenKey作为自定义参数传递,同时由DI容器填充其他参数。

如果IJWTAuthenticationManager必须是单身,请尝试注入IHttpContextAccessor

services.AddHttpContextAccessor();
services.AddSingleton<IJWTAuthenticationManager>(serviceProvider =>
    ActivatorUtilities.CreateInstance<JWTAuthenticationManager>(serviceProvider,tokenKey));

然后您的JWTAuthenticationManager类应如下所示:

public class JWTAuthenticationManager : IJWTAuthenticationManager
{
    private readonly string tokenKey;
    private readonly IRefreshTokenGenerator refreshTokenGenerator;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public JWTAuthenticationManager(
        string tokenKey,IRefreshTokenGenerator refreshTokenGenerator,IHttpContextAccessor httpContextAccessor)
    {
        this.tokenKey = tokenKey;
        this.refreshTokenGenerator = refreshTokenGenerator;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<AuthenticationResponse> Authenticate(string username,Claim[] claims)
    {
        // Resolve UserManager for current request
        var serviceProvider = _httpContextAccessor.HttpContext.RequestServices;
        var userManager = serviceProvider.GetRequiredService<UserManager<ibasis_apiUser>>();
        
        // The rest of your method
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-