-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement: Authentication and authorization for Blazor #4048
Comments
Some thoughts from the community here: https://brockallen.com/2019/01/11/using-oauth-and-oidc-with-blazor/ |
While we await official guidance, I wanted to share a decent authentication pattern I've been using:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorComponents<App.Startup>();
services.AddAuthentication(o => o.DefaultAuthenticateScheme = AzureADB2CDefaults.CookieScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));
}
services.AddHttpContextAccessor();
services.AddScoped<ClaimsPrincipal>(context => context.GetRequiredService<IHttpContextAccessor>()?.HttpContext?.User);
public IActionResult SignIn([FromRoute] string scheme)
{
scheme = scheme ?? AzureADB2CDefaults.AuthenticationScheme;
var redirectUrl = Url.Content("~/");
return Challenge(
new AuthenticationProperties { RedirectUri = redirectUrl },
scheme);
}
app.UseAuthentication();
app.UseMvcWithDefaultRoute();
@inject ClaimsPrincipal CurrentUser
<nav class="nav">
<a href="/" class="logo">
<img src="/images/logo.png" />
</a>
@if (CurrentUser.Identity.IsAuthenticated == false)
{
<div class="nav--right">
<button onclick=@SignIn style="padding-right: 20px;">Log In</button>
<!--If user is customer-->
<cart-mini>
</div>
}
else if (CurrentUser.IsInRole("Photographer"))
{
<div class="nav--center">
<a href="/Photographer" class="menu-item">Dashboard</a>
<a href="/Photographer/Cards" class="menu-item">Cards</a>
</div>
<div class="nav--right">
<a href="/Photographer/SalesHistory"><img src="~/images/icons/alert.png" alt="notifications" /></a>
<img src="@(CurrentUser.Avatar() ?? "~/images/avatar_512.png")" onclick=@ToggleDropdown class="profileImg" />
</div>
} This pattern ended up feeling cleaner to me than the cascading parameter that the Blazor Pizza workshop uses (https://github.com/dotnet-presentations/blazor-workshop/tree/master/src/BlazingPizza.ComponentsLibrary/Authentication), mainly because I don't like the look of using I also didn't like injecting |
And for authorization, what about an Something like this: @inject ClaimsPrincipal CurrentUser
@if (IsAuthorized())
{
@ChildContent
}
@functions {
[Parameter] string Roles { get; set; }
[Parameter] RenderFragment ChildContent { get; set; }
bool IsAuthorized()
{
if (!string.IsNullOrWhiteSpace(Roles))
{
var roles = Roles.Split(',').Select(x => x.Trim());
foreach (var role in roles)
{
if (CurrentUser.IsInRole(role)) return true;
}
return false;
}
return CurrentUser.Identity.IsAuthenticated;
}
} And used like this: <Authorize Roles="Photographer, Customer">
<div class="nav--center">
<a href="/Photographer" class="menu-item">Dashboard</a>
<a href="/Photographer/Cards" class="menu-item">Cards</a>
</div>
</Authorize>
<Authorize Roles="Customer">
<div class="nav--right">
<cart-mini></cart-mini>
</div>
</Authorize> |
@josephayoung regarding |
@josephayoung +1 for the ease of use we can get at the roles. Many SPA's these days have multi page scenarios like that these days, and being able to perform a simple role check in an if like that is an absolute bonus. Having the identity available globally too is a boon too, that way all we need is a simple inject. One thing that's also worth considering is attachment of roles to pages. It's all very well saying if(.. InRole("..") , but an interesting idea I borrowed from the AureliaJS frame work in all of my apps is the ability to attach the roles a page is allowed to have access it, in the router. In aurelia for example, when you create an entry in the routing data structure in your app base, you generally have something like the following:
Some stuff is mandatory, such as the route, the URL fragment, name etc but other stuff like "nav:true" and "auth:true", roles array etc are optional. If the optional stuff exists, then the router actually does the auth check on behalf of the user, before the page route is even routed to, and in aurelias case, if a route doesn't match, an event is raised giving the app developer the chance to catch the role fail, and take remedial action. |
I wanted to point out that I built a framework for authentication in BlazorEssentials. I have an AppStateBase that is injected into the app and handles dealing with the authentication cycle. Your app has a page that processes login hashes if you have to redirect elsewhere (like in Auth0), and you handle the authentication lifecycle events in AppStartup. I have this functioning properly (using Auth0) in a closed source app. I'm going to be adjusting the app registration to use the IOptions API + Microsoft DI to make it a little more fluent. But I think this, combined with either the Razor Component, or an [Authorize] attribute on the ViewModel (which I also demonstrate in BlazorEssentials) would work well too. Hope that helps! |
I'd be interested to know if there is a way to obtain the The only way I can see at present is to implement a Web API on to return the user details to the client if it requests them. |
There is no |
Wow thanks for the fast response @SteveSandersonMS - is that in Preview6 ? |
I am porting a React frontend application to Blazor and after reading this thread I will pause on the security side until it is supported. My current implementation in React is obtaining a JWT token and passing to Ocelot->API services using the ADAL library. Will Blazor support retreiving JWT tokens for the purpose of attaching to API calls? |
No @jrobertshawe I don't think it will - Steve's notes on Auth state
|
I feel it's important for client side applications to be able to easily send API calls with bearer token for authentication. Azure AD is commonly used to secure ASP.NET Core APIs. Have people tried using Azure AD (ADAL.JS library?) with Blazor to authenticate the API calls? |
The remaining work is going to be handled as part of #10698 |
and the custom validation class
i use [Authorize] attribute on a controller function for api and it always display the data , these attribute not working, when i debug the identity user i found it not authenticated but it always send the json data while it should sent not authenticated response, any help to know why the authorize attribute not working ?? |
Hi. It looks like you are posting on a closed issue!
|
Scope
This will be something similar to what the SPA templates have in terms of functionality.
We will try to simplify the amount of code and put it in libraries so it can be serviced.
Things to consider:
Design notes: https://gist.github.com/SteveSandersonMS/60ca3a5f70a7f42fba14981add7e7f79
The text was updated successfully, but these errors were encountered: