C# 如何在客户端获取DotNetOpenAuth.OAuth2返回的错误消息?
我正在使用C# 如何在客户端获取DotNetOpenAuth.OAuth2返回的错误消息?,c#,asp.net-web-api,dotnetopenauth,bearer-token,C#,Asp.net Web Api,Dotnetopenauth,Bearer Token,我正在使用ExchangeUserCredentialForToken函数从授权服务器获取令牌。当我的用户存在于我的数据库中时,它可以正常工作,但当凭据不正确时,我希望向客户端发回一条消息。我使用以下两行代码设置错误消息: context.SetError("Autorization Error", "The username or password is incorrect!"); context.Rejected(); 但是在客户端,我得到的只是协议错误(错误400)。您能帮助我如何在授权
ExchangeUserCredentialForToken
函数从授权服务器获取令牌。当我的用户存在于我的数据库中时,它可以正常工作,但当凭据不正确时,我希望向客户端发回一条消息。我使用以下两行代码设置错误消息:
context.SetError("Autorization Error", "The username or password is incorrect!");
context.Rejected();
但是在客户端,我得到的只是协议错误(错误400)。您能帮助我如何在授权服务器的服务器端获取错误消息集吗
来自授权服务器的完整应用程序配置:
using Constants;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Infrastructure;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using AuthorizationServer.Entities;
using AuthorizationServer.Entities.Infrastructure.Abstract;
using AuthorizationServer.Entities.Infrastructure.Concrete;
namespace AuthorizationServer
{
public partial class Startup
{
private IEmployeeRepository Repository;
public void ConfigureAuth(IAppBuilder app)
{
//instanciate the repository
Repository = new EmployeeRepository();
// Enable Application Sign In Cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Application",
AuthenticationMode = AuthenticationMode.Passive,
LoginPath = new PathString(Paths.LoginPath),
LogoutPath = new PathString(Paths.LogoutPath),
});
// Enable External Sign In Cookie
app.SetDefaultSignInAsAuthenticationType("External");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "External",
AuthenticationMode = AuthenticationMode.Passive,
CookieName = CookieAuthenticationDefaults.CookiePrefix + "External",
ExpireTimeSpan = TimeSpan.FromMinutes(5),
});
// Enable google authentication
app.UseGoogleAuthentication();
// Setup Authorization Server
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AuthorizeEndpointPath = new PathString(Paths.AuthorizePath),
TokenEndpointPath = new PathString(Paths.TokenPath),
ApplicationCanDisplayErrors = true,
#if DEBUG
AllowInsecureHttp = true,
#endif
// Authorization server provider which controls the lifecycle of Authorization Server
Provider = new OAuthAuthorizationServerProvider
{
OnValidateClientRedirectUri = ValidateClientRedirectUri,
OnValidateClientAuthentication = ValidateClientAuthentication,
OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
OnGrantClientCredentials = GrantClientCredetails
},
// Authorization code provider which creates and receives authorization code
AuthorizationCodeProvider = new AuthenticationTokenProvider
{
OnCreate = CreateAuthenticationCode,
OnReceive = ReceiveAuthenticationCode,
},
// Refresh token provider which creates and receives referesh token
RefreshTokenProvider = new AuthenticationTokenProvider
{
OnCreate = CreateRefreshToken,
OnReceive = ReceiveRefreshToken,
}
});
// indicate our intent to use bearer authentication
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AuthenticationType = "Bearer",
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active
});
}
private Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == Clients.Client1.Id)
{
context.Validated(Clients.Client1.RedirectUrl);
}
else if (context.ClientId == Clients.Client2.Id)
{
context.Validated(Clients.Client2.RedirectUrl);
}
return Task.FromResult(0);
}
private Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientname;
string clientpassword;
if (context.TryGetBasicCredentials(out clientname, out clientpassword) ||
context.TryGetFormCredentials(out clientname, out clientpassword))
{
employee Employee = Repository.GetEmployee(clientname, clientpassword);
if (Employee != null)
{
context.Validated();
}
else
{
context.SetError("Autorization Error", "The username or password is incorrect!");
context.Rejected();
}
}
return Task.FromResult(0);
}
private Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(new GenericIdentity(context.UserName, OAuthDefaults.AuthenticationType), context.Scope.Select(x => new Claim("urn:oauth:scope", x)));
context.Validated(identity);
return Task.FromResult(0);
}
private Task GrantClientCredetails(OAuthGrantClientCredentialsContext context)
{
var identity = new ClaimsIdentity(new GenericIdentity(context.ClientId, OAuthDefaults.AuthenticationType), context.Scope.Select(x => new Claim("urn:oauth:scope", x)));
context.Validated(identity);
return Task.FromResult(0);
}
private readonly ConcurrentDictionary<string, string> _authenticationCodes =
new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
private void CreateAuthenticationCode(AuthenticationTokenCreateContext context)
{
context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
_authenticationCodes[context.Token] = context.SerializeTicket();
}
private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context)
{
string value;
if (_authenticationCodes.TryRemove(context.Token, out value))
{
context.DeserializeTicket(value);
}
}
private void CreateRefreshToken(AuthenticationTokenCreateContext context)
{
context.SetToken(context.SerializeTicket());
}
private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}
}
}
使用常量;
使用Microsoft.Owin;
使用Microsoft.Owin.Security;
使用Microsoft.Owin.Security.Cookies;
使用Microsoft.Owin.Security.Infrastructure;
使用Microsoft.Owin.Security.OAuth;
使用Owin;
使用制度;
使用System.Collections.Concurrent;
使用System.Linq;
使用System.Security.Claims;
使用System.Security.Principal;
使用System.Threading.Tasks;
使用AuthorizationServer.Entities;
使用AuthorizationServer.Entities.Infrastructure.Abstract;
使用AuthorizationServer.Entities.Infrastructure.Concrete;
命名空间授权服务器
{
公共部分类启动
{
私人雇员存储库;
public void ConfigureAuth(IAppBuilder应用程序)
{
//实例化存储库
Repository=新员工Repository();
//启用应用程序登录Cookie
app.UseCookieAuthentication(新的CookieAuthenticationOptions
{
AuthenticationType=“应用程序”,
AuthenticationMode=AuthenticationMode.Passive,
LoginPath=新路径字符串(path.LoginPath),
LogoutPath=新路径字符串(path.LogoutPath),
});
//启用外部登录Cookie
app.setDefaultSignatureAuthenticationType(“外部”);
app.UseCookieAuthentication(新的CookieAuthenticationOptions
{
AuthenticationType=“外部”,
AuthenticationMode=AuthenticationMode.Passive,
CookieName=CookieAuthenticationDefaults.CookiePrefix+“外部”,
ExpireTimeSpan=从分钟(5)开始的时间跨度,
});
//启用google身份验证
app.UseGoogleAuthentication();
//设置授权服务器
app.useAuthorizationServer(新的OAuthorizationServerOptions
{
AuthorizeEndpointPath=新路径字符串(path.AuthorizePath),
TokenEndpointPath=新路径字符串(path.TokenPath),
ApplicationAndDisplayErrors=true,
#如果调试
AllowInsecureHttp=true,
#恩迪夫
//授权服务器提供程序,用于控制授权服务器的生命周期
Provider=新的OAuthAuthorizationServerProvider
{
OnValidateClientRedirectUri=ValidateClientRedirectUri,
OnValidateClientAuthentication=ValidateClientAuthentication,
OnGrantResourceOwnerCredentials=GrantResourceOwnerCredentials,
OnGrantClientCredentials=GrantClientCredentials详细信息
},
//创建和接收授权代码的授权代码提供程序
AuthorizationCodeProvider=新的AuthenticationTokenProvider
{
OnCreate=CreateAuthenticationCode,
OnReceive=ReceiveAuthenticationCode,
},
//刷新创建和接收referesh令牌的令牌提供程序
RefreshTokenProvider=新的AuthenticationTokenProvider
{
OnCreate=CreateRefreshToken,
OnReceive=ReceiverFreshToken,
}
});
//表明我们打算使用承载身份验证
app.useAuthBeareAuthentication(新的OAuthBeareAuthenticationOptions
{
AuthenticationType=“承载人”,
AuthenticationMode=Microsoft.Owin.Security.AuthenticationMode.Active
});
}
专用任务ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext上下文)
{
if(context.ClientId==Clients.Client1.Id)
{
context.Validated(Clients.Client1.RedirectUrl);
}
else if(context.ClientId==Clients.Client2.Id)
{
context.Validated(Clients.Client2.RedirectUrl);
}
返回Task.FromResult(0);
}
专用任务ValidateClientAuthentication(OAuthValidateClientAuthenticationContext)
{
字符串clientname;
字符串clientpassword;
if(context.TryGetBasicCredentials(out clientname,out clientpassword)||
TryGetFormCredentials(out clientname,out clientpassword))
{
employee=Repository.GetEmployee(clientname,clientpassword);
if(Employee!=null)
{
context.Validated();
}
其他的
{
SetError(“自动化错误”,“用户名或密码不正确!”);
context.Rejected();
}
}
返回Task.FromResult(0);
}
专用任务GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentials上下文)
{
var identity=newclaimsidentity(newgenericientity(context.UserName,OAuthDefaults.AuthenticationType),context.Scope.Select(x=>newclaim(“urn:oauth:Scope”,x));
上下文验证(身份);
返回Task.FromResult(0);
}
专用任务GrantClientCredetails(OAuthGrantClientCredentialsContext)
context.SetError("Account locked",
"You have exceeded the total allowed failed logins. Please try back in an hour.");
context.Rejected();
public static class ServerGlobalVariables
{
//Your other properties...
public const string OwinChallengeFlag = "X-Challenge";
}
//Set the error message
context.SetError("Account locked",
"You have exceeded the total allowed failed logins. Please try back in an hour.");
//Add your flag to the header of the response
context.Response.Headers.Add(ServerGlobalVariables.OwinChallengeFlag,
new[] { ((int)HttpStatusCode.Unauthorized).ToString() });
//This class handles all the OwinMiddleware responses, so the name should
//not just focus on invalid authentication
public class CustomAuthenticationMiddleware : OwinMiddleware
{
public CustomAuthenticationMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
if (context.Response.StatusCode == 400
&& context.Response.Headers.ContainsKey(
ServerGlobalVariables.OwinChallengeFlag))
{
var headerValues = context.Response.Headers.GetValues
(ServerGlobalVariables.OwinChallengeFlag);
context.Response.StatusCode =
Convert.ToInt16(headerValues.FirstOrDefault());
context.Response.Headers.Remove(
ServerGlobalVariables.OwinChallengeFlag);
}
}
}
app.Use<CustomAuthenticationMiddleware>();
//Need to create a class to deserialize the Json
//Create this somewhere in your application
public class OAuthErrorMsg
{
public string error { get; set; }
public string error_description { get; set; }
public string error_uri { get; set; }
}
//Need to make sure to include Newtonsoft.Json
using Newtonsoft.Json;
//Code for your object....
private void login()
{
try
{
var state = _webServerClient.ExchangeUserCredentialForToken(
this.emailTextBox.Text,
this.passwordBox.Password.Trim(),
scopes: new string[] { "PublicProfile" });
_accessToken = state.AccessToken;
_refreshToken = state.RefreshToken;
}
catch (ProtocolException ex)
{
var webException = ex.InnerException as WebException;
OAuthErrorMsg error =
JsonConvert.DeserializeObject<OAuthErrorMsg>(
ExtractResponseString(webException));
var errorMessage = error.error_description;
//Now it's up to you how you process the errorMessage
}
}
public static string ExtractResponseString(WebException webException)
{
if (webException == null || webException.Response == null)
return null;
var responseStream =
webException.Response.GetResponseStream() as MemoryStream;
if (responseStream == null)
return null;
var responseBytes = responseStream.ToArray();
var responseString = Encoding.UTF8.GetString(responseBytes);
return responseString;
}
context.SetError("Autorization Error", "The username or password is incorrect!");
context.Response.Headers.Add("AuthorizationResponse", new[] { "Failed" });
public class InvalidAuthenticationMiddleware : OwinMiddleware
{
public InvalidAuthenticationMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
if (context.Response.StatusCode == 400 && context.Response.Headers.ContainsKey("AuthorizationResponse"))
{
context.Response.Headers.Remove("AuthorizationResponse");
context.Response.StatusCode = 401;
}
}
}
app.Use<InvalidAuthenticationMiddleware>();
public class InvalidAuthenticationMiddleware : OwinMiddleware
{
public InvalidAuthenticationMiddleware(OwinMiddleware next) : base(next) { }
public override async Task Invoke(IOwinContext context)
{
context.Response.OnSendingHeaders(state =>
{
var response = (OwinResponse)state;
if (!response.Headers.ContainsKey("AuthorizationResponse") && response.StatusCode != 400) return;
response.Headers.Remove("AuthorizationResponse");
response.StatusCode = 401;
}, context.Response);
await Next.Invoke(context);
}
}