Blazor: IServiceCollection does not contain a definition for AddDefaultIdentity

Francesco Iapicca picture Francesco Iapicca · Jun 3, 2019 · Viewed 10.7k times · Source

following this tutorialI've encountered a problem in the Startup.cs file:

(need to scroll down a bit, sorry)

the issue is with default identity, getting the following error:

"IServiceCollection does not contain a definition for AddDefaultIdentity and no accessible extension method AddDefaultIdentity accepting a first argument of type" IServiceCollection could be found(are you missing a using directive or an assembly reference?)"

I looked up the documentation, but I'm missing what error I'm making, I've seen a bunch of cases similar to mine, but their solution (included) doesn't seems to work. I can us some help, thanks in advance.

"my" code is HERE if you want to take a look

Answer

enet picture enet · Jun 3, 2019

You shouldn't add identity if you use Jwt autentication...Note: AddDefaultIdentity extension method is used to add the default UI service for Razor Pages and MVC. And it also requires you to add StaticFiles.

Note also the additional code and its arrangement in the Configure method

Try this in your startup class:

 public class Startup
{
    //add
    public IConfiguration Configuration { get; }
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }


    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddNewtonsoftJson();

        services.AddTransient<IJwtTokenService, JwtTokenService>();


        //Setting up Jwt Authentication
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = Configuration["Jwt:Issuer"],
                    ValidAudience = Configuration["Jwt:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
                };
            });


        services.AddResponseCompression(opts =>
        {
            opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "application/octet-stream" });
        });
    }

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

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBlazorDebugging();
            }

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(routes =>
     {
         routes.MapDefaultControllerRoute();
     });

    app.UseBlazor<Client.Startup>();
        }
    }

}

Hope this helps...

Update 1: * Update your Startup class with the code above * Annotate your SampleDataController controller like this:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 
[Route("api/[controller]")]
    public class SampleDataController : Controller
    {
    // ..
    }
  • Run your application, and then post a get http request in Postman or Fiddler for the url:

api/SampleData/WeatherForecasts

The response should contain the created JwtToken

Summary of the flow of execution: Posting a get request to your Web Api. The request to the route point WeatherForecasts is redirected to the Token controller whose purpose is to create a Jwt token and return it to the caller. Note that this controller does not verify the identity of the the user on whose behalf this request was send...

TO DO:

  • Create a service to store the Jwt token: This service can use Blazor extensions for LocalStorage and SessionStorage to store and retrieve Jwt Tokens. This service may contain methods such as IsAutenticated, GetToken, etc.

Note: That you may pass the Jwt Token from the server to Blazor with more details about the user as a cookie.

  • Create a Login Component to login the user, if he is not already logged in and tries to access secure resource

Note: If the user is already authenticated, he's not redirected to the Login form. Instead we issue an http request to the server, in order to retrieve the rsources needed in Blazor, if that is the case.

Note: How do we know if our user is authenticated ? We query our IsAutenticated method. If the user is authenticated, if retrieve the Jwt Token and add it to the headers collection passed with our HttpClient call.

More to come...

Do you see it ?