I have a web application and a web API in pure .NET Core (no references to the old stuff). Both sides use Azure Active Directory in order to authorize the users.
In my Web application, I have this:
[Authorize]
public string GetApiData()
{
// ...
string userObjectID = (user.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID, session));
ClientCredential credential = new ClientCredential(ClientId, ClientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(ApiResourceId, credential);
// Get all the user's permissions
using (var client = new HttpClient())
{
var address = $"{Constants.API_BASE_ADDR}/api/{data}";
using (var request = new HttpRequestMessage(HttpMethod.Get, address))
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
var response = await client.SendAsync(request);
// ...
}
}
}
public class NaiveSessionCache : TokenCache
{
private static readonly object FileLock = new object();
string UserObjectId = string.Empty;
string CacheId = string.Empty;
ISession Session = null;
public NaiveSessionCache(string userId, ISession session)
{
UserObjectId = userId;
CacheId = UserObjectId + "_TokenCache";
Session = session;
this.AfterAccess = AfterAccessNotification;
this.BeforeAccess = BeforeAccessNotification;
Load();
}
public void Load()
{
lock (FileLock)
{
this.Deserialize(Session.Get(CacheId));
}
}
public void Persist()
{
lock (FileLock)
{
// reflect changes in the persistent store
Session.Set(CacheId, this.Serialize());
// once the write operation took place, restore the HasStateChanged bit to false
this.HasStateChanged = false;
}
}
// Empties the persistent store.
public override void Clear()
{
base.Clear();
Session.Remove(CacheId);
}
public override void DeleteItem(TokenCacheItem item)
{
base.DeleteItem(item);
Persist();
}
// Triggered right before ADAL needs to access the cache.
// Reload the cache from the persistent store in case it changed since the last access.
void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
Load();
}
// Triggered right after ADAL accessed the cache.
void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (this.HasStateChanged)
{
Persist();
}
}
}
And on the API side:
[Authorize]
[HttpGet("{data}"))]
public string Get(string data)
{
// How to get authorized User information?
// ...
}
Now, all of that works. The challenge I'm facing is being able to get what user is calling the Get method on the API side. The only things I've found that seem somewhat useful is the Bearer token, and what is assigned to userObjectID on the web side.
However, I need, at a minimum, the user's email address, although having access to everything like I do on the web app side would be nice.
Here's what is in the User.Claims enumerable on the API side:
[0]: {aud: https://constco.onmicrosoft.com/API}
[1]: {iss: https://sts.windows.net/84fa7f[REDACTED]/}
[2]: {iat: 1483853522}
[3]: {nbf: 1483853522}
[4]: {exp: 1483857422}
[5]: {appid: 7d491[REDACTED]}
[6]: {appidacr: 1}
[7]: {e_exp: 10800}
[8]: {http://schemas.microsoft.com/identity/claims/identityprovider: https://sts.windows.net/84fa7f[REDACTED]/}
[9]: {http://schemas.microsoft.com/identity/claims/objectidentifier: 22b491[REDACTED]}
[10]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 22b491[REDACTED]}
[11]: {http://schemas.microsoft.com/identity/claims/tenantid: 84fa7f[REDACTED]}
[12]: {ver: 1.0}
And doing something like User.Identity.Name just gives null.
So, how can I get which user is calling into the API, using pure .NET Core?
Note: On the API side, I've tried inheriting from Controller and ApiController, and neither provided any better information.
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameclaim was added, User.Identity.Name should return its name and email as user name (if you add email too)