为Bearer授权添加额外的逻辑
我正在尝试实施OWIN持票人令牌授权,并基于这篇文章 。 但是,在承载令牌中我需要一条额外的信息,我不知道如何实现。
在我的应用程序中,我需要从持有者令牌中推断出用户信息(比如userid)。 这很重要,因为我不希望授权用户能够充当其他用户。 这可行吗? 它甚至是正确的方法吗? 如果用户标识是guid,那么这很简单。 在这种情况下,它是一个整数。 授权用户可能只是通过猜测/暴力来冒充他人,这是不可接受的。
看看这段代码:
public void ConfigureOAuth(IAppBuilder app) { OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new SimpleAuthorizationServerProvider() }; // Token Generation app.UseOAuthAuthorizationServer(OAuthServerOptions); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); } public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); using (AuthRepository _repo = new AuthRepository()) { IdentityUser user = await _repo.FindUser(context.UserName, context.Password); if (user == null) { context.SetError("invalid_grant", "The user name or password is incorrect."); return; } } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("sub", context.UserName)); identity.AddClaim(new Claim("role", "user")); context.Validated(identity); } }
我认为可以覆盖授权/认证以适应我的需要吗?
您的代码中似乎缺少某些内容。
你没有validation你的客户。
您应该实现ValidateClientAuthentication并在那里检查客户端的凭据。
这就是我做的:
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { string clientId = string.Empty; string clientSecret = string.Empty; if (!context.TryGetBasicCredentials(out clientId, out clientSecret)) { context.SetError("invalid_client", "Client credentials could not be retrieved through the Authorization header."); context.Rejected(); return; } ApplicationDatabaseContext dbContext = context.OwinContext.Get(); ApplicationUserManager userManager = context.OwinContext.GetUserManager(); if (dbContext == null) { context.SetError("server_error"); context.Rejected(); return; } try { AppClient client = await dbContext .Clients .FirstOrDefaultAsync(clientEntity => clientEntity.Id == clientId); if (client != null && userManager.PasswordHasher.VerifyHashedPassword(client.ClientSecretHash, clientSecret) == PasswordVerificationResult.Success) { // Client has been verified. context.OwinContext.Set("oauth:client", client); context.Validated(clientId); } else { // Client could not be validated. context.SetError("invalid_client", "Client credentials are invalid."); context.Rejected(); } } catch (Exception ex) { string errorMessage = ex.Message; context.SetError("server_error"); context.Rejected(); } }
这里有一篇很好的文章。
在这个博客系列中可以找到更好的解释。
更新 :
我做了一些挖掘和webstuff是对的。
为了将errorDescription
传递给客户端,我们需要在使用SetError
设置错误之前拒绝:
context.Rejected(); context.SetError("invalid_client", "The information provided are not valid !"); return;
或者我们可以在描述中通过序列化的json对象扩展它:
context.Rejected(); context.SetError("invalid_client", Newtonsoft.Json.JsonConvert.SerializeObject(new { result = false, message = "The information provided are not valid !" })); return;
使用javascript/jQuery
客户端,我们可以反序列化文本响应并读取扩展消息:
$.ajax({ type: 'POST', url: '', data: { username: 'John', password: 'Smith', grant_type: 'password' }, dataType: "json", contentType: 'application/x-www-form-urlencoded; charset=utf-8', xhrFields: { withCredentials: true }, headers: { 'Authorization': 'Basic ' + authorizationBasic }, error: function (req, status, error) { if (req.responseJSON && req.responseJSON.error_description) { var error = $.parseJSON(req.responseJSON.error_description); alert(error.message); } } });
另外,如果要设置自定义错误消息,则必须交换context.Rejected
和context.SetError
的顺序。
// Summary: // Marks this context as not validated by the application. IsValidated and HasError // become false as a result of calling. public virtual void Rejected();
如果在context.Rejected
之后放置context.Rejected
,那么属性context.HasError
将重置为false,因此使用它的正确方法是:
// Client could not be validated. context.Rejected(); context.SetError("invalid_client", "Client credentials are invalid.");
只是为了添加LeftyX的答案,这里是如何在上下文被拒绝后完全控制发送给客户端的响应。 注意代码注释。
根据Greg P的原始答案 ,进行一些修改
第1步:创建一个充当中间件的类
using AppFunc = System.Func, System.Threading.Tasks.Task>;
namespace SignOnAPI.Middleware.ResponseMiddleware {
public class ResponseMiddleware { AppFunc _next; ResponseMiddlewareOptions _options; public ResponseMiddleware(AppFunc nex, ResponseMiddlewareOptions options) { _next = next; } public async Task Invoke(IDictionary environment) { var context = new OwinContext(environment); await _next(environment); if (context.Response.StatusCode == 400 && context.Response.Headers.ContainsKey("Change_Status_Code")) { //read the status code sent in the response var headerValues = context.Response.Headers.GetValues("Change_Status_Code"); //replace the original status code with the new one context.Response.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault()); //remove the unnecessary header flag context.Response.Headers.Remove("Change_Status_Code"); } } }
第2步:创建扩展类(可以省略)。
此步骤是可选的,可以修改为接受可以传递给中间件的选项。
public static class ResponseMiddlewareExtensions { //method name that will be used in the startup class, add additional parameter to accept middleware options if necessary public static void UseResponseMiddleware(this IAppBuilder app) { app.Use(); } }
步骤3:修改OAuthAuthorizationServerProvider
实现中的GrantResourceOwnerCredentials
方法
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); if () { //first reject the context, to signify that the client is not valid context.Rejected(); //set the error message context.SetError("invalid_username_or_password", "Invalid userName or password" ); //add a new key in the header along with the statusCode you'd like to return context.Response.Headers.Add("Change_Status_Code", new[] { ((int)HttpStatusCode.Unauthorized).ToString() }); return; } }
步骤4:在启动类中使用此中间件
public void Configuration(IAppBuilder app) { app.UseResponseMiddleware(); //configure the authentication server provider ConfigureOAuth(app); //rest of your code goes here.... }
- 自定义授权属性在WebAPI中不起作用
- 从Service Fabric WebAPI控制器写入ServiceEventSource
- GROUP BY / Case Asp.Net Web API ODATA的不敏感扩展?
- 如何使用swagger swashbuckle保护生成的API文档
- 为什么IIS返回空响应?
- 如何在WebAPI后端C#上接收JSON数据?
- 使用MultipartFormDataStreamProvider和ReadAsMultipartAsync
- Web API – 在DbContext类中访问HttpContext
- JWT和Web API(JwtAuthForWebAPI?) – 寻找一个例子