C# Webapi获取承载令牌
我正在使用asp.NETWebAPI进行练习,希望提供独立的授权服务 因此,我实现了基于令牌的授权服务(owin)和数据提供者服务。现在我想覆盖数据提供程序服务中的Authorize属性。它必须从当前请求中获取承载令牌,向授权服务发出请求,接收有关用户及其角色的信息 问题是:如何在我的自定义属性中获得不记名令牌,也许有更好的方法来进行这种“令牌转移” 我想这样使用它:C# Webapi获取承载令牌,c#,asp.net-web-api2,C#,Asp.net Web Api2,我正在使用asp.NETWebAPI进行练习,希望提供独立的授权服务 因此,我实现了基于令牌的授权服务(owin)和数据提供者服务。现在我想覆盖数据提供程序服务中的Authorize属性。它必须从当前请求中获取承载令牌,向授权服务发出请求,接收有关用户及其角色的信息 问题是:如何在我的自定义属性中获得不记名令牌,也许有更好的方法来进行这种“令牌转移” 我想这样使用它: //data service [CustomAttribute (Roles = "admin")] public IEnume
//data service
[CustomAttribute (Roles = "admin")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
public class CustomAttribute : System.Web.Mvc.AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext context)
{
using (WebClient client = new WebClient())
{
string bearerToken;
//somehow get token
client.Headers.Add("Authorization", "Bearer " + bearerToken);
string userinfo = client.DownloadString("authURL/GetUserInfo");
CustomUser user = JsonConvert.DeserializeObject<CustomUser>(userinfo);
if (!user.Roles == this.Roles)
{
//return 401
}
}
}
}
// authorization service
public async Task<UserInfoResponse> GetUserInfo()
{
var owinContext = HttpContext.Current.GetOwinContext();
int userId = owinContext.Authentication.User.Identity.GetUserId<int>();
var response = new UserInfoResponse()
{
UserId = userId.ToString(),
Roles = await UserManager.GetRolesAsync(userId)
};
return response;
}
//数据服务
[CustomAttribute(Roles=“admin”)]
公共IEnumerable Get()
{
返回新字符串[]{“value1”,“value2”};
}
公共类CustomAttribute:System.Web.Mvc.AuthorizeAttribute
{
授权时的公共覆盖无效(授权上下文)
{
使用(WebClient=newWebClient())
{
弦乐演奏者;
//不知怎么弄到了代币
客户。标题。添加(“授权”、“持票人”+持票人);
string userinfo=client.DownloadString(“authURL/GetUserInfo”);
CustomUser=JsonConvert.DeserializeObject(userinfo);
如果(!user.Roles==this.Roles)
{
//返回401
}
}
}
}
//授权服务
公共异步任务GetUserInfo()
{
var owinContext=HttpContext.Current.GetOwinContext();
int userId=owinContext.Authentication.User.Identity.GetUserId();
var response=newuserinforesponse()
{
UserId=UserId.ToString(),
角色=等待UserManager.GetRolesAsync(用户ID)
};
返回响应;
}
要回答有关如何访问请求授权标头中的承载令牌的特定问题,请执行以下操作:
public class CustomAttribute : System.Web.Mvc.AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext context)
{
System.Net.Http.Headers.AuthenticationHeaderValue authorizationHeader = context.HttpContext.Request.Headers.Authorization;
// Check that the Authorization header is present in the HTTP request and that it is in the
// format of "Authorization: Bearer <token>"
if ((authorizationHeader == null) || (authorizationHeader.Scheme.CompareTo("Bearer") != 0) || (String.IsNullOrEmpty(authorizationHeader.Parameter)))
{
// return HTTP 401 Unauthorized
}
using (WebClient client = new WebClient())
{
client.Headers.Add("Authorization", "Bearer " + authorizationHeader.Parameter);
string userinfo = client.DownloadString("authURL/GetUserInfo");
CustomUser user = JsonConvert.DeserializeObject<CustomUser>(userinfo);
if (!user.Roles == this.Roles)
{
// I recommend return HTTP 403 Forbidden here, not 401. At this point
// the request has been authenticated via the bearer token, but the
// authenticated client does not have sufficient roles to execute the
// request, so they are forbidden from doing so. HTTP 401 Unauthorized
// is a bit of a misnomer because the actual intention is to determine
// whether or not the request is authenticated. HTTP 401 also implies
// that the request should be tried again with credentials, but that
// has already been done!
}
}
}
}
公共类CustomAttribute:System.Web.Mvc.AuthorizeAttribute
{
授权时的公共覆盖无效(授权上下文)
{
System.Net.Http.Headers.AuthenticationHeaderValue authorizationHeader=context.HttpContext.Request.Headers.Authorization;
//检查HTTP请求中是否存在授权标头,以及该标头是否位于
//“授权:持票人”格式
if((authorizationHeader==null)| |(authorizationHeader.Scheme.CompareTo(“承载人”)!=0)| |(String.IsNullOrEmpty(authorizationHeader.Parameter)))
{
//未经授权返回HTTP 401
}
使用(WebClient=newWebClient())
{
client.Headers.Add(“Authorization”、“bearier”+authorizationHeader.Parameter);
string userinfo=client.DownloadString(“authURL/GetUserInfo”);
CustomUser=JsonConvert.DeserializeObject(userinfo);
如果(!user.Roles==this.Roles)
{
//我建议在这里返回HTTP403,而不是401
//请求已通过承载令牌进行身份验证,但
//经过身份验证的客户端没有足够的角色来执行
//请求,因此禁止他们这样做。HTTP 401未经授权
//这有点用词不当,因为实际意图是确定
//请求是否经过身份验证。HTTP 401还意味着
//应使用凭据重试该请求,但
//已经完成了!
}
}
}
}
可能有更好的方法来完成您正在尝试做的事情,但我对MVC方面的事情以及应用程序的身份验证/授权工作流了解不够,因此无法提供一个很好的答案。至少这有助于知道在授权属性中从何处找到标题值。正如Blair Allen所说,有更好的方法来完成我想要的。使用IdentityServer4生成令牌,只需检查令牌签名,无需任何其他请求。我切换到NetCore,这里是mvc客户端的解决方案:接收令牌并将其保存在cookie中
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
var tokenResult = await AuthService.LoginUserAsync(model.Email, model.Password);
if(!tokenResult.IsSuccess)
{
ModelState.AddModelError("","Wrong email or password");
return View(model);
}
Response.Cookies.Append("access_token", tokenResult.AccessToken, new CookieOptions(){
HttpOnly = true,
SameSite = SameSiteMode.Strict,
Secure = true
});
return RedirectToAction("Index", "Home");
}
你看过这个吗?承载令牌应与客户端一起存储,并随每个请求一起发送到数据提供程序。您所说的“自定义属性”是什么意思?我指的是System.Web.Mvc.AuthorizationAttribute,具有授权的重写方法(AuthorizationContext)
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, config =>
{
config.Authority = configuration["TokenServerUrl"];
config.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var token = context.HttpContext.Request.Cookies["access_token"];
context.Token = token;
return Task.CompletedTask;
},
};
config.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = configuration["TokenServerUrl"],
ValidateLifetime = true,
};
});