Given an asp.net core api and working firebase auth using only the [Authorize] attribute, how can I add custom claims to the token to use [Authorize(Policy = "admin")]? The admin SDK is only available for node.js, Java, python or go and I can't find any docs on how to use the Firebase Admin API directly. From my understanding the user claims have to be stored in the Firebase Auth backend.
Since the Firebase Admin .NET SDK 1.1 is released the Control Access With Custom Claims feature is supported.
You can find the repository here: https://github.com/firebase/firebase-admin-dotnet
Setup guide and documentation: https://firebase.google.com/docs/admin/setup
Solution:
// Initialize the admin SDK with your service account keys
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("path/to/serviceAccountKey.json"),
});
// Create the custom user claim that has the role key
var claims = new Dictionary<string, object>
{
{ ClaimTypes.Role, "Administrator" }
};
// This will call the Firebase Auth server and set the custom claim for the user
await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(uid, claims);
To the best of my knowledge, with the C# Firebase Admin SDK you can't. I had the same issue and, at first, I used the token to get the user id, retrieved the roles for the user id from the database, set up a Claims array, and created a custom token with the added claims with the . Then I sent it to Firebase via their REST API to get a regular Firebase ID and Refresh token as explained in the reference guide. Finally i gave the token to the client. However, I had issues (mostly 404 errors) ad it is not well documented what changes you need to make to the verification middleware to accept the new reissued tokens, and I was never able to get the refresh Token as it was never in the REST API response. I even followed the steps in here and here and minted my own custom token according to Firebase instructions, but was never able to make the darn thing work.
So I ended up doing something a little different. I retrieved the user claims from the firebase IdToken and created my own token using using System.IdentityModel.Tokens.Jwt. There I added my own claims and roles and sent that to the client. Now the client logs in using FireBase but i have full control of the tokens to use my API
This is how I modified the startup. Keep in mind I haven't played with all options
var key = System.Text.Encoding.UTF8.GetBytes(Configuration["MyToken:Key"]);
services.AddAuthentication(
auth => {
auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;})
.AddJwtBearer(options => {
options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true
};
});
this is the simplified Encoding function :
public string EncodeTokenMS(string uid, Claim[] claims)
{
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(<Secret key here>));
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature);
var now = DateTimeOffset.UtcNow;
var _claims = new[] {
new Claim(JwtRegisteredClaimNames.Iss, "https://auth.xxx.com"),
new Claim(JwtRegisteredClaimNames.Aud, "https://auth.xxx.com"),
new Claim(JwtRegisteredClaimNames.Sub, uid),
new Claim(JwtRegisteredClaimNames.AuthTime, now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64),
new Claim(JwtRegisteredClaimNames.Iat, now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64),
new Claim(JwtRegisteredClaimNames.Exp, now.AddMinutes(60).ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64),
// TODO Actually write the code to get tenancy, roles, and user info
new Claim("tenantId", "PippoBaudo" ),
new Claim(ClaimTypes.Role, "User")
};
//Create and sign the JWT, and write it to a string
var jwt = new JwtSecurityToken(
claims: _claims,
signingCredentials: signingCredentials);
return new JwtSecurityTokenHandler().WriteToken(jwt);
}
The drawback of this approach is there is an added roundtrip when the user signs up, however it is only when the user needs a token so it shouldn't add a great deal of latency, and I can increase the lifetime of the token to more than 60 minutes.
Suggestions and (constructive) comments on this approach are welcomed!
Hope this helps!
来源:https://stackoverflow.com/questions/51231972/add-user-claims-to-firebase-auth-from-asp-net-core-api