Web Api 2,Claims always null in my inheritance Apicontroller - api

I am using the Web Api 2 Auth template in my project.I want to get the user id when the client request with Api Key. My question is :
1 How can I get the api client user's Id.
-Is right or wrong resolve it through the Api requesting ?
-or take the userId in the http header directly?
-or query it from database using the Api key?
2 I create the MyApiController inherit from ApiController,I want to get the claims in it.So I write some code in it.like this
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
var principal = Request.GetRequestContext().Principal as ClaimsPrincipal;
CorpId = (from c in principal.Claims where c.Type.Contains("CorpId") select c.Value).FirstOrDefault();
UserId = (from c in principal.Claims where c.Type.Contains("UserId") select c.Value).FirstOrDefault();
}
I found the claim is null in the MyApiController. But when I do it in the action controller,It worked ?

You'd rather get request specific data when the request is executed (i.e. in Controller.Get method), not when the controller is created. Or use a filter attribute if values are not needed in controller method.

Related

Cannot change the parameters in the API endpoint key

I am a new Xamarin developer. I am trying to integrate a data API to my Xamarin forms cross-platform mobile app.
Following is the site that I get my URL endpoint: navigate to the website
Following is the API endpoint I get from the above site: https://api.tidesandcurrents.noaa.gov/api/prod/datagetterdate=latest&station=8518750&product=air_temperature&datum=MTL&time_zone=gmt&units=metric&format=json
The API endpoint URL sends back data when based on the weather station IDparameter in the API endpoint. The problem is that it is hardcoded in the API endpoint itself. Therefore, I must change the whole API endpoint when I need to request data from another weather station ID.
I have no idea how to send the stationID as a variable in the same URL, like in following end point I got from openweather API service:
http://api.openweathermap.org/data/2.5/weatherlat{location.Latitude}&lon{location.Longitude}&appid=d6533ef259a2c612eb50836b198fc366&units=metric
In the above API, I can send the longitude and latitude as parameters via the API key and get relevant information. But in my API key, I cannot see such a way to send a 'StationID' as a parameter.
Can somebody please help me to modify my following code to send the 'stationID' as a variable and get data dynamically based on the station ID please?
Following is my code for getting API data send them to the .xaml front end.
private async void GetTideInfo()
{
var url = $"https://api.tidesandcurrents.noaa.gov/api/prod/datagetter?date=latest&station=8518750&product=air_temperature&datum=MTL&time_zone=gmt&units=metric&format=json";
var result = await ApiCaller.Get(url);
if (result.Successful)
{
var tidalInfo = JsonConvert.DeserializeObject<TidleRoot>(result.Response);
meanTideTxt.Text = tidalInfo.data[0].v + " m";
}
else
{
await DisplayAlert("Tidal data", "No tidal data found", "OK");
}
}
Thanks in advance for everybody who volunteer to solve my problem.
just insert the StationID value into the url
var stationId = 8518750;
var url = $"https://api.tidesandcurrents.noaa.gov/api/prod/datagetterdate=latest&station={stationId}&product=air_temperature&datum=MTL&time_zone=gmt&units=metric&format=json";

.net core 3.1 & identity issue (claims nameidentifier has an id that doesn't match any user, while claims name is right)

I'm having an issue in an area of my website where i need to retrieve the user Id, i tried both by using the HttpContext.User and the injected IHttpContextAccessor, both give me an id that 1) doesn't match the user and 2) doesn't even exist in my database!
I also tried injecting a UserManager and calling GetUserId on it and that too gives me the wrong id (once again, no clue where from, it's not in the database). Calling GetUserAsync on it returns null.
I'm not using anything special nor fancy, the default page included with idendity core to log in, just a context that inherits from IdentityDbContext, and the login part works just fine as those pages are behind an Authorize tag and do force me to log in. If i was getting an error to begin with i could dig but i'm just getting an Id that seems to come from nowhere and am at a loss at where to look.
Here's what the claims look like when calling
HttpContext.User.Claims.ToList()
[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: f478bf7a-1734-494c-aad6-0882ab24007f} <-- this id is not present in AspNetUsers table
[1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: EDITED OUT FOR PRIVACY} <-- my correct username (my email)
[2]: {AspNet.Identity.SecurityStamp: EDITED OUT}
[3]: {http://schemas.microsoft.com/ws/2008/06/identity/claims/role: Administrator} <-- correctly finds my role too
You can use the following code to get the UserId
using System.Security.Claims;
using Microsoft.AspNetCore.Identity;
var claimsIdentity = (ClaimsIdentity)this.User.Identity;
var claim = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
var userId = claim.Value;
I had that problem for using this in ExternalLoginCallback:
var user = new SmileAppUser { UserName = email, Email = email };
await _signInManager.SignInAsync(user, isPersistent: false);
Try to retrieve the user from the database to include the id in the claims with SignInAsync.

How to get the current TraceId and SpanId

This article, https://devblogs.microsoft.com/aspnet/improvements-in-net-core-3-0-for-troubleshooting-and-monitoring-distributed-apps/, tells me that the field TraceId is available as a correlation id, which is great!
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
=> ConnectionId:0HLR1BR0PL1CH
=> RequestPath:/weatherforecastproxy
RequestId:0HLR1BR0PL1CH:00000001,
SpanId:|363a800a-4cf070ad93fe3bd8.,
TraceId:363a800a-4cf070ad93fe3bd8,
ParentId: Executed endpoint 'FrontEndApp.Controllers.WeatherForecastProxyController.Get
(FrontEndApp)'
In fact, I can see that in our log sink this works as advertised: When web application A serves a request and in doing so invokes web application B, both of them write the same TraceId value to the log.
As far as I understand, any ASP.NET Core application that receives an incoming Request-Id header will attach the same header to outgoing requests, but if the header does not exist on the incoming request, an new value will be generated for the outgoing request.
We have been asked to add that value to the response from web application A, but it is (not surprisingly) not available on the incoming request.
I have been looking at the System.Diagnostics.Activity class, but accessing Activity.Current isn't giving me an instance with anything useful - the TraceID is just {} - i.e. empty.
My question is this: How can I access the TraceId value in the context of a web application?
-S
I had the same problem when I tried to add a header with TraceId value.
Doing some tests with ModelValidation, I saw then in this kind of error response the "traceId" value was correct, but I couldn't obtain this value from http context variable in any way.
Then I went to net core source code to see DefaultProblemDetailsFactory implementation and surprise! The "traceId" value is obtained doing this:
var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
Yes, you can get THE traceId using Activity static variable.
You can get tracid and spanid in dictionary.
using var subject = _tracer.BuildSpan($"Operation").StartActive();
var spanContext = subject.Span.Context;
var dictionary = new Dictionary<string, string>();
_tracer.Inject(spanContext, BuiltinFormats.TextMap, new TextMapInjectAdapter(dictionary));

Retrieving client name in IdentityServer4 and ASP.NET Core

The dbo.Clients table in the IdentityServer database contains both ClientId and ClientName, however requesting a client credentials token doesn't include the client name in the token.
Is there a way to either retrieve client information from IdentityServer given the client id, or request that the client name be added to the token?
You can add them dynamically using a custom token request validator :
public class ClaimClientsUpdated : ICustomTokenRequestValidator
{
public Task ValidateAsync(CustomTokenRequestValidationContext context)
{
context.Result.ValidatedRequest.Client.AlwaysSendClientClaims = true;
context.Result.ValidatedRequest.ClientClaims.Add(new Claim("name", context.Result.ValidatedRequest.Client.ClientName));
return Task.FromResult(0);
}
}
Register in DI :
services.AddTransient<ICustomTokenRequestValidator, ClaimClientsUpdated>();
It will add prefix "client_" to custom claims , so claim will be "client_name": "value" in access token .
You can add information about the client in general by adding claims to the ClientClaims table. E.g. Type = Name, Value = MyCustomName
Which is added as claim (assuming prefix client_):
"client_Name": "MyCustomName"
This will allow you to add information about the client without having to add or change code.
The drawback for the client name is that you'll have to add a claim with redundant information, as Clients.ClientName is not the source. The advantage is that it's configuration only.

Get User Info From Access Token WebApi Asp.net Core

I'm using the new ASP.NET Core Identity API Authorization found in dotnet-core3-preview, the docs are found here https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-3.0
I'm succesfully running the typical login process, and the token are set and sent in the Bearer token. However rightnow I have an api end point that should return some user details from the database, so I'm trying to extract the user id from the token to query the database.
Yet, I'm not able to find the id in any of the claims, as per my screenshot below, how can I accomplish this?
[HttpGet]
[Authorize]
public async Task<IActionResult> GetUserByToken(){
var ls = User.Claims.AsQueryable();
return Ok(ls);
}
The user id could be find in claim : http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier :
var userID = User.Claims.Where(a => a.Type == ClaimTypes.NameIdentifier).FirstOrDefault().Value;
That id value equals Id column in AspNetUsers table which created by ASP.NET Identity .
I prefer using this instead which is shorter:
var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value