简体   繁体   中英

Blazor WASM: Add JWT auth with custom API

I have built an API that controls some smart home stuff. To prevent the whole internet from doing so, I added authentication using JWT / Bearer. The API contains endpoints for the smart home stuff aswell as some user management: API endpoints for users

The login will return a JWT token if credentials were valid. It is also built using .NET 6:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(x =>
    {
        x.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidateAudience = false,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
        };
    });

Login Controller:

[HttpPost]
public async Task<IActionResult> Login([FromBody] UserLogin login)
{
    var user = await _userService.GetUser(login.Username);
    if (user is not null && _userService.IsPasswordCorrect(user, login.Password))
    {
        var tokens = await _userService.GetJwtAndRefreshToken(user);
        return Ok(new LoginResponse { JWT = tokens.Jwt, RefreshToken = tokens.Refreshtoken });
    }
    return Unauthorized("Wrong username or password!");
}

Now I am trying to build a frontend for this app using blazor. When creating the app, i used the option "individual user accounts" for authentication. It is documented here: https://docs.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/standalone-with-authentication-library?view=aspnetcore-6.0&tabs=visual-studio

This created the following in the blazow WASM app:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

builder.Services.AddOidcAuthentication(options =>
{
    // Configure your authentication provider options here.
    // For more information, see https://aka.ms/blazor-standalone-auth
    builder.Configuration.Bind("Local", options.ProviderOptions);
});

await builder.Build().RunAsync();

appsettings.json looks like this:

{
  "Local": {
    "Authority": "https://localhost:7110/login",
    "ClientId": "33333333-3333-3333-33333333333333333"
  }
}

I changed the Authority to my login api url, but doesn't seem to be enough. Clicking on the login button that was added by default fires this request: Request

Is there a simple way to use the MS Authorization framework with my custom api?

I spent great amount of time on this. These are my notes from it. Note that I am using IdentityServer. Probably a lot of stuff will be different for you. But it should at least guide you what to check.

It works (for me), but best-practise is not garantee.

My API address is on port 5001 , Client is on port 5101

For Client project

  • Change HttpClient address in Client. Change Http MessageHandler. Change address for public client
var clientBaseAddress = new Uri(builder.Configuration["apiurl"] ?? throw new ArgumentNullException("apirul is null (reading from config file)"));

builder.Services.AddHttpClient("BlazorApp6.ServerAPI", client =>client.BaseAddress = clientBaseAddress)
         .AddHttpMessageHandler(sp =>
         {//this is need when api is separated. https://code-maze.com/using-access-token-with-blazor-webassembly-httpclient/
             var handler = sp.GetService<AuthorizationMessageHandler>()!
             .ConfigureHandler(
                 authorizedUrls: new[] { builder.Configuration["HttpMessageHandlerAuthorizedUrls"] },
                 scopes: new[] { "BlazorApp6.ServerAPI" }
              );
             return handler;
         });
builder.Services.AddHttpClient<PublicClient>(client => client.BaseAddress = clientBaseAddress);

  • Add HttpMessageHandlerAuthorizedUrls apiurl to appsettings (example for developement):

     "apiurl": "https://localhost:5001", "HttpMessageHandlerAuthorizedUrls": "https://localhost:5001",
  • Program.cs AddApiAuthorization is different (set opt.ProviderOptions.ConfigurationEndpoint)

     builder.Services.AddApiAuthorization( //this line is only when address of api consumer is different opt => opt.ProviderOptions.ConfigurationEndpoint = builder.Configuration["ApiAuthorizationConfigurationEndpoint"] ).AddAccountClaimsPrincipalFactory<CustomUserFactory>();
  • Add ApiAuthorizationConfigurationEndpoint to appsettings

     "ApiAuthorizationConfigurationEndpoint": "https://localhost:5001/_configuration/BlazorApp6.Client"
  • Change launchSetting to different port

    "applicationUrl": "https://localhost:5101;http://localhost:5100",

For api project

  • Add cors to client app

    string developmentCorsPolicy = "dev_cors"; services.AddCors(opt => { opt.AddPolicy(name: developmentCorsPolicy, builder => { builder.WithOrigins("https://localhost:5101", "https://localhost:5201").WithMethods("GET", "POST", "PUT", "DELETE").AllowAnyHeader(); }); }); //... if (app.Environment.IsDevelopment()) app.UseCors(developmentCorsPolicy);
  • There is probably some need to add cors for identiy server, but it works without it .

    • in case it is needed:

       services.AddSingleton<ICorsPolicyService>((container) => { var logger = container.GetRequiredService<ILogger<DefaultCorsPolicyService>>(); return new DefaultCorsPolicyService(logger) { AllowAll = true }; });
  • Change appsettings IdentityServer section to have some info about client.

    • This info is obtained in OidcController with requests starting _configuration:

       "IdentityServer": { "Clients": { "BlazorApp6.Client": { "Profile": "SPA", "LogoutUri": "https://localhost:5101/authentication/logout-callback", "RedirectUri": "https://localhost:5101/authentication/login-callback" }, }, "Key": { "Type": "Development" } }
    • Note that Profile has changed to SPA (instead of IdentityServerSPA, which means hosted)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM