Aspnetcore.docs: Examples on how to recover user name and ID

Created on 22 Mar 2020  Â·  16Comments  Â·  Source: dotnet/AspNetCore.Docs

It would be helpful to add examples on how to recover user ID and name from within the server/controller code, since, with the proposed configuration, the traditional UserManager methods fail.


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Blazor P1 Source - Docs.ms doc-enhancement

All 16 comments

Hello @AlbertoPa ... Yes, I think examples or cross-links would be helpful. The component-side concepts are covered higher up in the Blazor Security Overview topic ... https://docs.microsoft.com/en-us/aspnet/core/security/blazor/

Depending on your scenario, you'll take one or both of the following approaches:

  • AuthorizeView component ... provides a context that will give you access to the user.
  • AuthenticationStateProvider class ... grab the user from the authentication state by calling GetAuthenticationStateAsync.

Like this ......

@page  "/getname"
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

<h3>GetName</h3>

<AuthorizeView>
    <Authorized>
        <p>Name: @context.User.Identity.Name</p>
    </Authorized>
    <NotAuthorized>
        <p>Name: You haven't logged in yet.</p>
    </NotAuthorized>
</AuthorizeView>

<p>@_nameMessage</p>

@code {
    private string _nameMessage;

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            _nameMessage = $"Name: {user.Identity.Name}";
        }
        else
        {
            _nameMessage = "Name: You haven't logged in yet.";
        }
    }
}

I'll improve this aspect of all of the docs in this node. All of these new Blazor WebAssembly authn/z topics use the same general approach.

Leave this issue open. It will close automatically when the PR merges. Thanks for commenting on the topic. I'll ping you on the PR.

@AlbertoPa ... I note that you said "server/controller" code in your question. Let me know if you weren't asking about _components_ because my answer above applies to the component-side of the scenario. On the server-side (the Server API), we might need to ask engineering for further clarification if you're hitting a problem. I'm not particularly familiar with Identity Server myself. I naively think that the normal Identity Server approaches work (and we link off to the IS docs for the specifics).

I think I have a repro of the scenario now. I'm not getting the user from UserManager<ApplicationUser> in the WeatherForecastController with a using BlazorAppIdentityServer.Server.Models. I'll hack around with it a bit more, but we might need help to sort it out.

... and I tried .AddAspNetIdentity<ApplicationUser>() without luck ... the service/package is already provided.

... feels more like their IProfileService bit should work for this.

I moved this issue back to _Triage_ so that Artak can take a look next Friday.

Artak TL;DR ... It looks like Identity Server has a Profile Service "for allowing claims to be dynamically loaded as needed for a user," but I'm not familiar with how it would be used in the Server API in our Blazor Hosted scenario. If we go with an example of this scenario (whatever approach is valid), I'll probably need some tips from an Identity Server :cat2:. For example in the WeatherForecastController, I'm not sure what would be passed for ProfileDataRequestContext when calling GetProfileDataAsync.

Thank you @guardrex !
Indeed my issue is with recovering user information within a controller in the app.server, as you tried in WeatherController.cs. I am using "local user accounts" in the Blazor webassembly template (hosted).
All I get looking at the object in VS object inspector is that the user is authenticated.

I would have expected the usual:

ApplicationUser user = await _userManager.GetUserAsync(User);

to return the user, but while User has some info, user is null. User.Name is also null.
I tried adding claims in

services.AddDefaultIdentity<ApplicationUser>(
    options =>
    {
     ...
    }

as I would normally do, but it didn't seem to make any difference.

Yes, that's my experience, too. I tried adding a custom claim to see if it would show up ... no 🎲🎲.

You could try the normal support channels. I'm sure that an Identity Server/API expert out there can provide a solution or some tips. If you get an answer, please do post it back here.

I'll find some time to do some additional research on this. Post back if you get a solution.

Will do! Thanks again.

I made some progress, after some inspection in VS. It is possible to retrieve the user ID with:

string userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;

No luck (yet!) with the user name, but I thought of sharing what I found so far.

Yes ... that's a claim that I see on user (listed as claim 5 here) ...

claims

Yes. This is sufficient to check the user identity and authorize based on ID. The remaining part of the issue is how to add other claims, in case one wants to verify them (user name, etc.), which does not seem to work with the usual approach.

Thanks!

@AlbertoPa Try https://github.com/dotnet/AspNetCore.Docs/issues/17517#issue-590009500 ...

services.Configure<IdentityOptions>(options => 
    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

EDIT ~I'm going to move that issue over to engineering to see what Javier says about it.~ Actually, I think I'll just ping him on that issue. If that will be documented for Identity Server, too (same solution works for both non-IS and IS scenarios), I'll close that issue and work it from here (since that issue will essentially be a duplicate of this one).

Yes @AlbertoPa ... add that IdentityOptions configuration and ...

var user = await _userManager.GetUserAsync(User);

... will yield a correct user.UserName.

I'm not sure at this point if they'll add the IdentityOptions config to the template, but I think 🤔 that we'll at least need to have that temporarily in the topic for the server-side gestures.

EDIT In addition, I was also able to get user.Email and user.PhoneNumber.

EDIT 2X ... and I checked the claims server-side ... yes, they're all there ... the confirms, lockout, two-factor, etc.

@guardrex Thanks!

This line still needs to be added to the Server App Configuration section under the Startup class section:

services.Configure(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

This line is discussed under this feedback thread but it was never added to the topic. The line is needed to make the GetUserAsync(User) work.

By the way, thanks for adding this example. Until I came here I was quite frustrated trying to figure out how to get my user info on the server.

@jlinstrum Would you mind opening a new issue for that from the bottom of the topic ... the This page feedback button+form. It will create a new issue for me to work.

You can just put the link to your comment in the body of the issue ...

https://github.com/dotnet/AspNetCore.Docs/issues/17402#issuecomment-611220730
Was this page helpful?
0 / 5 - 0 ratings

Related issues

davisnw picture davisnw  Â·  3Comments

Rick-Anderson picture Rick-Anderson  Â·  3Comments

Raghumu picture Raghumu  Â·  3Comments

AnthonyMastrean picture AnthonyMastrean  Â·  3Comments

aaron-bozit picture aaron-bozit  Â·  3Comments