ASP.NET 身份角色声明缺失
ASP.NET Identity Role claims missing
我正在使用 Duende IdentityServer 通过 Google 登录,它也配置为使用 ASP.NET 用户角色身份等
Google IdentityServer 配置:
.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "redacted"
options.ClientSecret = "redacted";
});
Blazor UI 授权配置:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
options.Authority = "myidentityserverurl";
options.ClientId = "web2";
options.ClientSecret = "secret";
options.UsePkce = true;
options.ResponseType = "code";
options.Scope.Add("api1");
options.Scope.Add("roles");
options.ClaimActions.MapUniqueJsonKey("role", "role");
options.ClaimActions.MapUniqueJsonKey("roles", "role");
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = JwtClaimTypes.Role,
ValidateAudience = false
};
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
});
API 授权配置:
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Authority = "myidentityserverurl";
options.Audience = "api1";
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = JwtClaimTypes.Role,
ValidateAudience = false
};
});
我有一个 Blazor UI 客户端,它可以通过 Google 成功登录,它返回一个 Cookie、一个 access_token 和一个 id_token.
从 Google 登录返回的 access_token 没有来自 ASP.NET 身份的任何 role
声明,无论是来自 Blazor 还是来自 Postman。
如果我在通过 google 登录后在 IdentityServer 中调用 /connect/userinfo
,我会按预期获得我所处的角色:
{
"sub": "subhere",
"name": "myname",
"role": "SystemAdministrator",
"preferred_username": "uuid from google"
}
在 Blazor 应用程序中,如果我从 httpContextAccessor.HttpContext.User.Claims
获得声明,我会按预期获得 role
声明。
如果我使用作为登录 UI 的一部分发出的访问令牌调用我的 API,并得到如下声明:
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
我在这里没有任何 role
声明。同样,在通过 Google.
登录后,Postman 的不记名令牌中也没有 role
声明
以下是 API 的声明,缺少我的 role
声明:
[
{
"type": "iss",
"value": "myidentityserverurl"
},
{
"type": "nbf",
"value": "1653401427"
},
{
"type": "iat",
"value": "1653401427"
},
{
"type": "exp",
"value": "1653405027"
},
{
"type": "aud",
"value": "https://myidentityserverurl/resources"
},
{
"type": "scope",
"value": "openid"
},
{
"type": "scope",
"value": "profile"
},
{
"type": "scope",
"value": "api1"
},
{
"type": "scope",
"value": "roles"
},
{
"type": "http://schemas.microsoft.com/claims/authnmethodsreferences",
"value": "external"
},
{
"type": "client_id",
"value": "web2"
},
{
"type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"value": "uuidhere"
},
{
"type": "auth_time",
"value": "1653401425"
},
{
"type": "http://schemas.microsoft.com/identity/claims/identityprovider",
"value": "Google"
},
{
"type": "sid",
"value": "A9E0A3B55D35FDAE3A7DCA0126C34E75"
},
{
"type": "jti",
"value": "43C218D3076EA595B4647CD7B369C405"
}
]
我已经尝试了几天来修复,但我 运行 没有想法。我想我在这里遗漏了一些基本的东西。
我想你可以阅读相关文档:
http://docs.identityserver.io/en/latest/reference/profileservice.html#profile-service
并尝试如下:
public class ProfileServices : IProfileService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _roleManager;
public ProfileServices(
UserManager<ApplicationUser> userManager,
RoleManager<ApplicationRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public async Task<List<Claim>> GetClaimsFromUserAsync(ApplicationUser user)
{
var claims = new List<Claim> {
new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
new Claim(JwtClaimTypes.PreferredUserName,user.UserName)
};
var role = await _userManager.GetRolesAsync(user);
role.ToList().ForEach(f =>
{
claims.Add(new Claim(JwtClaimTypes.Role, f));
});
return claims;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
var user = await _userManager.FindByIdAsync(subjectId);
context.IssuedClaims =await GetClaimsFromUserAsync(user);
}
public async Task IsActiveAsync(IsActiveContext context)
{
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
var user = await _userManager.FindByIdAsync(subjectId);
context.IsActive = user != null;
}
}
在startup.cs中注册:
services.AddScoped<IProfileService, ProfileService>();
我正在使用 Duende IdentityServer 通过 Google 登录,它也配置为使用 ASP.NET 用户角色身份等
Google IdentityServer 配置:
.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "redacted"
options.ClientSecret = "redacted";
});
Blazor UI 授权配置:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
options.Authority = "myidentityserverurl";
options.ClientId = "web2";
options.ClientSecret = "secret";
options.UsePkce = true;
options.ResponseType = "code";
options.Scope.Add("api1");
options.Scope.Add("roles");
options.ClaimActions.MapUniqueJsonKey("role", "role");
options.ClaimActions.MapUniqueJsonKey("roles", "role");
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = JwtClaimTypes.Role,
ValidateAudience = false
};
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
});
API 授权配置:
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Authority = "myidentityserverurl";
options.Audience = "api1";
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = JwtClaimTypes.Role,
ValidateAudience = false
};
});
我有一个 Blazor UI 客户端,它可以通过 Google 成功登录,它返回一个 Cookie、一个 access_token 和一个 id_token.
从 Google 登录返回的 access_token 没有来自 ASP.NET 身份的任何 role
声明,无论是来自 Blazor 还是来自 Postman。
如果我在通过 google 登录后在 IdentityServer 中调用 /connect/userinfo
,我会按预期获得我所处的角色:
{
"sub": "subhere",
"name": "myname",
"role": "SystemAdministrator",
"preferred_username": "uuid from google"
}
在 Blazor 应用程序中,如果我从 httpContextAccessor.HttpContext.User.Claims
获得声明,我会按预期获得 role
声明。
如果我使用作为登录 UI 的一部分发出的访问令牌调用我的 API,并得到如下声明:
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
我在这里没有任何 role
声明。同样,在通过 Google.
role
声明
以下是 API 的声明,缺少我的 role
声明:
[
{
"type": "iss",
"value": "myidentityserverurl"
},
{
"type": "nbf",
"value": "1653401427"
},
{
"type": "iat",
"value": "1653401427"
},
{
"type": "exp",
"value": "1653405027"
},
{
"type": "aud",
"value": "https://myidentityserverurl/resources"
},
{
"type": "scope",
"value": "openid"
},
{
"type": "scope",
"value": "profile"
},
{
"type": "scope",
"value": "api1"
},
{
"type": "scope",
"value": "roles"
},
{
"type": "http://schemas.microsoft.com/claims/authnmethodsreferences",
"value": "external"
},
{
"type": "client_id",
"value": "web2"
},
{
"type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"value": "uuidhere"
},
{
"type": "auth_time",
"value": "1653401425"
},
{
"type": "http://schemas.microsoft.com/identity/claims/identityprovider",
"value": "Google"
},
{
"type": "sid",
"value": "A9E0A3B55D35FDAE3A7DCA0126C34E75"
},
{
"type": "jti",
"value": "43C218D3076EA595B4647CD7B369C405"
}
]
我已经尝试了几天来修复,但我 运行 没有想法。我想我在这里遗漏了一些基本的东西。
我想你可以阅读相关文档: http://docs.identityserver.io/en/latest/reference/profileservice.html#profile-service
并尝试如下:
public class ProfileServices : IProfileService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _roleManager;
public ProfileServices(
UserManager<ApplicationUser> userManager,
RoleManager<ApplicationRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public async Task<List<Claim>> GetClaimsFromUserAsync(ApplicationUser user)
{
var claims = new List<Claim> {
new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
new Claim(JwtClaimTypes.PreferredUserName,user.UserName)
};
var role = await _userManager.GetRolesAsync(user);
role.ToList().ForEach(f =>
{
claims.Add(new Claim(JwtClaimTypes.Role, f));
});
return claims;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
var user = await _userManager.FindByIdAsync(subjectId);
context.IssuedClaims =await GetClaimsFromUserAsync(user);
}
public async Task IsActiveAsync(IsActiveContext context)
{
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
var user = await _userManager.FindByIdAsync(subjectId);
context.IsActive = user != null;
}
}
在startup.cs中注册:
services.AddScoped<IProfileService, ProfileService>();