抱歉我的英文。
我有三个项目:IdentityServer,Ensino.Mvc,Ensino.Api。 IdentityServer项目提供主要身份信息和声明 - 声明配置文件,声明地址,声明Sid ...等,来自IdentityServer4库。 Ensino.Mvc项目在令牌中获取此信息并将其发送到API,以便MVC获得对资源的访问权限。令牌包含IdentityServer提供的所有声明。但是在API中,我需要生成API特定的其他声明,例如:声明与令牌中的声明Sid相对应的EnrollmentId。此外,我想在HttpContext中添加此声明以供将来使用。有人能告诉我如何实现这个目标吗?
我在Startup.ConfigureServices中有这段代码:
def reports_engagement_device_archive():
selectList = []
selectString = ""
devicesList = [
"aoldesktop|4|AOL Desktop",
"aolmail|14|AOL Mail",
"appleipad|24|Apple iPad",
"appleiphone|34|Apple iPhone",
"applemail|44|Apple Mail",
"blackberry|54|BlackBerry",
"gmail|64|Gmail",
"googleandroid|74|Google Android",
"icloud|84|iCloud",
"officethreesixfive|394|Office 365",
"other|94|Other",
"outlook|104|Outlook",
"outlookcom|114|Outlook.com",
"samsungemailapp|124|Samsung Email App",
"samsungemailapp|134|Samsung Mail",
"thunderbird|364|Thunderbird",
"webversion|144|Web version",
"windowslivemail|154|Windows Live Mail",
"windowsmail|164|Windows Mail",
"windowsphone|174|Windows Phone",
"yahoomail|184|Yahoo! Mail"
]
for devString in devicesList:
(tblName, devID, devName) = devString.split("|")
dropMySQLTable("temp_" + tblName ,verbose)
selectList.append("""(SELECT SUM(t.total) FROM temp_""" + tblName + """ AS t WHERE t.mailingID=s.mailingID) AS \"""" + devName + """\"""")
db.sql("""
CREATE TABLE temp_""" + tblName + """ AS (
SELECT s.mailingID,SUM(l.averageReadTime) AS "total" FROM eventlog AS l
INNER JOIN recipients AS r ON l.recipientKey=r.id
INNER JOIN sends AS s ON l.mailingIDKey=s.id
WHERE r.commonDeviceKey=""" + devID + """ AND l.averageReadTime!="-1" AND l.averageReadTime!="(none)" AND (s.sendDateTime BETWEEN '""" + startDate + """' AND '""" + endDate + """')
GROUP BY s.mailingID
);
""", verbose)
selectString = ",".join(selectList)
dropMySQLTable("t1" ,verbose)
db.sql("""
CREATE TABLE t1 AS (
SELECT DISTINCT
s.mailingID AS "mailingID"
s.TFPIDSanitised AS "TFPID Sanitised",
(SELECT SUM(l2.averageReadTime) FROM eventlog AS l2 INNER JOIN sends as s2 ON l2.mailingIDKey=s2.id WHERE s2.TFPIDSanitised=s.TFPIDSanitised AND l2.averageReadTime!="-1" AND l2.averageReadTime!="(none)") AS "Total",
""" + selectString + """
FROM sends AS s
WHERE s.TFPIDSanitised IS NOT NULL
AND (s.sendDateTime BETWEEN '""" + startDate + """' AND '""" + endDate + """')
);
""", verbose)
for devString in devicesList:
(tblName, devID, devName) = devString.split("|")
dropMySQLTable("temp_" + tblName ,verbose)
在其他项目中,没有API,只有mvc,我已继承// Add identity services
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5100";
options.RequireHttpsMetadata = false;
options.ApiName = "beehouse.scope.ensino-api";
});
// Add mvc services
services.AddMvc();
并覆盖UserClaimsPrincipalFactory
以添加其他声明。我喜欢在API项目中做这样的事情。有可能吗?
这样做的最佳方法是什么?
编辑:经过一些研究,我想做的是:IdentityServer认证,并根据声明和特定的api数据库数据在api中设置授权。答案 0 :(得分:4)
在您的API项目中,您可以将自己的事件处理程序添加到options.JwtBearerEvents.OnTokenValidated
。这是ClaimsPrincipal
已设置的点,您可以向标识添加声明或向主体添加新标识。
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5100";
options.RequireHttpsMetadata = false;
options.ApiName = "beehouse.scope.ensino-api";
options.JwtBearerEvents.OnTokenValidated = async (context) =>
{
var identity = context.Principal.Identity as ClaimsIdentity;
// load user specific data from database
...
// add claims to the identity
identity.AddClaim(new Claim("Type", "Value"));
};
});
请注意,这将在每次API请求时运行,因此如果您从数据库加载信息,最好缓存声明。
此外,Identity Server应该只负责识别用户,而不是他们的用户。他们所做的是特定于应用程序(角色,权限等),因此您正确认识到这一点并避免与Identity Server进行逻辑交叉。
答案 1 :(得分:1)
使用AuthenticationHandler
创建自己的IdentityServerAuthenticationHandler
将是最佳选择。这将允许您使用DI,拒绝身份验证,并在不需要时跳过自定义身份验证处理程序。
首先验证令牌然后添加更多声明的示例AuthenticationHandler
:
public class MyApiAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// Pass authentication to IdentityServerAuthenticationHandler
var authenticateResult = await Context.AuthenticateAsync("Bearer");
// If token authentication fails, return immediately
if (!authenticateResult.Succeeded)
{
return authenticateResult;
}
// Get user ID from token
var userId = authenticateResult.Principal.Claims
.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject)?.Value;
// Do additional checks for authentication
// e.g. lookup user ID in database
if (userId == null)
{
return AuthenticateResult.NoResult();
}
// Add additional claims
var identity = authenticateResult.Principal.Identity as ClaimsIdentity;
identity.AddClaim(new Claim("MyClaim", "MyValue"));
return authenticateResult;
}
}
为服务添加处理程序:
services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
// ...
})
.AddScheme<AuthenticationSchemeOptions, MyApiAuthenticationHandler>("MyApiScheme", null);
现在你可以使用任何一种方案:
// Authenticate token and get extra API claims
[Authorize(AuthenticationSchemes = "MyApiScheme")]
// Authenticate just the token
[Authorize(AuthenticationSchemes = "Bearer")]
请注意,IdentityServerAuthenticationHandler
执行相同的操作,using the dotnet JWT handler:
public class IdentityServerAuthenticationHandler : AuthenticationHandler<IdentityServerAuthenticationOptions>
{
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
...
return await Context.AuthenticateAsync(jwtScheme);
...
}
}
答案 2 :(得分:0)
一步一步确定:
options.ApiName
,但我建议您在此处发布代码时隐藏此类信息)。它应与您的new ApiResource("beehouse.scope.ensino-api", "My test resource", new List<string>() { "claim1", "claim2" });
这两个步骤都描述为here,但主要的是在添加资源时可以执行以下操作:
new Client
{
ClientId = "client",
.
.
// scopes that client has access to
AllowedScopes = { "beehouse.scope.ensino-api" }
.
.
}
然后在您的客户端配置中:
autoCropImage(url){
var img = new Image();
const cropApp = this;
let x = img.onload = function(){
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
const center_X = img.width/2, center_Y = img.height/2;
let init_X=0, init_Y=0;
ctx.drawImage(img, init_X, init_Y, img.width, img.height, 0, 0, img.width, img.height);
let dataUrl = canvas.toDataURL("image/jpeg", 1.0);
let dataUrl_short = dataUrl.replace("data:image/jpeg;base64,", "");
return dataUrl;
}();
img.src=url;
console.log(x);
return x;
}
//log result:
//data:,
这会将与此资源关联的声明添加到令牌。 当然,您必须在Identity Server级别设置此声明,但根据您的说法,您已经知道如何执行此操作。