如何使用网络中的过滤器传递带有错误消息的状态 api
how to pass the status with error message using Filters in web api
我不知道我在哪里失踪如果用户名和密码错误,我会被卡住发送错误消息。我的服务运行良好,如果用户 ID 和密码与 200 状态不匹配并且手动创建的状态成功,我可以手动发送错误消息。这是我创建的代码 HandleRequest
class
public class HandleRequest : Attribute, IAuthenticationFilter
{
public string Realm { get; set; }
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
//throw new NotImplementedException();
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
string status = await SendAsync(request, cancellationToken);
if (context.Request.RequestUri.LocalPath == "/Login/UserLogin")
{
return;
}
else if (authorization == null)
{
// No authentication was attempted (for this authentication method).
// Do not set either Principal (which would indicate success) or ErrorResult (indicating an error).
context.ErrorResult = new AuthenticationFailureResult("Null auth token..", request);
return;
}
else if (status == "Success")
{
return;
}
else
{
context.ErrorResult = new AuthenticationFailureResult("Invalid auth token..", request);
return;
}
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
Challenge(context);
return Task.FromResult(0);
}
private void Challenge(HttpAuthenticationChallengeContext context)
{
string parameter;
if (String.IsNullOrEmpty(Realm))
{
parameter = null;
}
else
{
// A correct implementation should verify that Realm does not contain a quote character unless properly
// escaped (precededed by a backslash that is not itself escaped).
parameter = "realm=\"" + Realm + "\"";
}
context.ChallengeWith("Basic", parameter);
}
public virtual bool AllowMultiple
{
get { return false; }
}
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
public async Task<string> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string status = "";
HttpStatusCode statusCode;
string token;
//determine whether a jwt exists or not
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
//allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
//return base.SendAsync(request, cancellationToken);
}
try
{
string sec = WebConfigurationManager.AppSettings["sec"];
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
SecurityToken securityToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = "http://localhost:1987",
ValidIssuer = "http://localhost:1987",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
LifetimeValidator = this.LifetimeValidator,
IssuerSigningKey = securityKey
};
//extract and assign the user of the jwt
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var id = int.Parse(identity.Claims.Where(c => c.Type == "id")
.Select(c => c.Value).SingleOrDefault());
bool isValidToken = IsValidToken(id, userName, type);
if (isValidToken == true)
{
status = "Success";
}
else
{
statusCode = HttpStatusCode.Unauthorized;
status = "Unauthorized";
}
}
catch (SecurityTokenValidationException e)
{
e.Message.ToString();
statusCode = HttpStatusCode.Unauthorized;
status = "Unauthorized";
}
catch (Exception ex)
{
ex.Message.ToString();
statusCode = HttpStatusCode.InternalServerError;
status = "InternalServerError";
}
return status;
}
public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
private bool IsValidToken(int? id, string userName, string type)
{
bool isValid = false;
using (MCSDEMOEntities con = new MCSDEMOEntities())
{
var GetUserDatails = (from u in con.ios_Users
where u.ID == id && u.LOGIN == userName && u.TYPEDESCR == type
select u).ToList();
if (GetUserDatails.Count == 1)
{
isValid = true;
}
else
{
isValid = false;
}
}
return isValid;
}
}
public static class HttpRequestHeadersExtensions
{
public static void Set(this HttpRequestHeaders headers, string name, string value)
{
if (headers.Contains(name)) headers.Remove(name);
headers.Add(name, value);
}
}
public static class HttpAuthenticationChallengeContextExtensions
{
public static void ChallengeWith(this HttpAuthenticationChallengeContext context, string scheme)
{
ChallengeWith(context, new AuthenticationHeaderValue(scheme));
}
public static void ChallengeWith(this HttpAuthenticationChallengeContext context, string scheme, string parameter)
{
ChallengeWith(context, new AuthenticationHeaderValue(scheme, parameter));
}
public static void ChallengeWith(this HttpAuthenticationChallengeContext context, AuthenticationHeaderValue challenge)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result);
}
}
public class AddChallengeOnUnauthorizedResult : IHttpActionResult
{
public AuthenticationHeaderValue Challenge { get; private set; }
public IHttpActionResult InnerHttpResult { get; private set; }
public AddChallengeOnUnauthorizedResult(AuthenticationHeaderValue challenge, IHttpActionResult innerResult)
{
Challenge = challenge;
InnerHttpResult = innerResult;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = await InnerHttpResult.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
// Only add one challenge per authentication scheme.
if (!response.Headers.WwwAuthenticate.Any((h) => h.Scheme == Challenge.Scheme))
{
response.Headers.WwwAuthenticate.Add(Challenge);
}
}
return response;
}
}
public class AuthenticationFailureResult : IHttpActionResult
{
public string ReasonPhrase { get; private set; }
public HttpRequestMessage Request { get; private set; }
public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(execute());
}
private HttpResponseMessage execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
response.ReasonPhrase = ReasonPhrase;
return response;
}
}
我的webapi config file
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
//check each request
config.Filters.Add(new HandleRequest());
// configuration for json reponse
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
//LoginController
// Login Model
config.Routes.MapHttpRoute(
name: "LoginApi",
routeTemplate: "{controller}/{action}",
defaults: new { controller = "Login", action = "UserLogin", id = RouteParameter.Optional }
);
}
和我的登录控制器
public class LoginController : ApiController
{
LoginModel logMod = new LoginModel();
LoginResponse logResp = new LoginResponse();
[HttpPost]
public LoginResponse UserLogin(LoginRequest logReq)
{
logResp = logMod.UserLogin(logReq );
return logResp;
}
}
登录模式class
public LoginResponse UserLogin(LoginRequest LogReq)
{
LoginResponse logResp = new LoginResponse();
try
{
if (LogReq.userName != "" && LogReq.password != "")
{
using (MCSDEMOEntities DataModel = new MCSDEMOEntities())
{
var UserDetails = (from user in DataModel.ios_Users
where (user.LOGIN == LogReq.userName && user.PASSWORD == LogReq.password && user.ACTIVE != 0)
select new
{
user.ID,
user.TYPEDESCR,
user.USERNAME
}).ToList();
if (UserDetails.Count != 0)
{
foreach (var Udetails in UserDetails)
{
logResp.id = Udetails.ID;
logResp.type = Udetails.TYPEDESCR;
logResp.userName = Udetails.USERNAME;
}
//create jwt token.
logResp.userToken = createToken(logResp.id, logResp.type, LogReq.userName);
logResp.Status = "Success";
}
else
{
logResp.Status = "401";
//throw new HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest);
// throw new AuthenticationFailureResult("","")
}
}
}
else
{
logResp.Status = "No Condition Match";
}
}
catch (Exception ex)
{
logResp.Status = ex.Message.ToString();
}
return logResp;
}
在上面的代码中,它很好地执行了服务,但即使用户 ID 和密码不匹配,它也会发送 http-200 ok 消息和我的状态 - json 中的 401。我想通过代码 401
传递 http
您需要 return HttpResponseMessage
来自您的 api 以便您可以使用状态等其他信息包装您的响应对象
[HttpPost]
public HttpResponseMessage UserLogin(LoginRequest logReq)
{
logResp = logMod.UserLogin(logReq );
// Decide based on your logic. This is
// a mock example.
var status = HttpStatusCode.OK
return Request.CreateResponse(HttpStatusCode.OK, logResp);
}
您可以在此处找到更多信息:https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results
引自:
HttpResponseMessage Convert directly to an HTTP response
Other type Write the serialized return value into the response body; return 200 (OK).
我不知道我在哪里失踪如果用户名和密码错误,我会被卡住发送错误消息。我的服务运行良好,如果用户 ID 和密码与 200 状态不匹配并且手动创建的状态成功,我可以手动发送错误消息。这是我创建的代码 HandleRequest
class
public class HandleRequest : Attribute, IAuthenticationFilter
{
public string Realm { get; set; }
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
//throw new NotImplementedException();
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
string status = await SendAsync(request, cancellationToken);
if (context.Request.RequestUri.LocalPath == "/Login/UserLogin")
{
return;
}
else if (authorization == null)
{
// No authentication was attempted (for this authentication method).
// Do not set either Principal (which would indicate success) or ErrorResult (indicating an error).
context.ErrorResult = new AuthenticationFailureResult("Null auth token..", request);
return;
}
else if (status == "Success")
{
return;
}
else
{
context.ErrorResult = new AuthenticationFailureResult("Invalid auth token..", request);
return;
}
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
Challenge(context);
return Task.FromResult(0);
}
private void Challenge(HttpAuthenticationChallengeContext context)
{
string parameter;
if (String.IsNullOrEmpty(Realm))
{
parameter = null;
}
else
{
// A correct implementation should verify that Realm does not contain a quote character unless properly
// escaped (precededed by a backslash that is not itself escaped).
parameter = "realm=\"" + Realm + "\"";
}
context.ChallengeWith("Basic", parameter);
}
public virtual bool AllowMultiple
{
get { return false; }
}
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
public async Task<string> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string status = "";
HttpStatusCode statusCode;
string token;
//determine whether a jwt exists or not
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
//allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
//return base.SendAsync(request, cancellationToken);
}
try
{
string sec = WebConfigurationManager.AppSettings["sec"];
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
SecurityToken securityToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = "http://localhost:1987",
ValidIssuer = "http://localhost:1987",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
LifetimeValidator = this.LifetimeValidator,
IssuerSigningKey = securityKey
};
//extract and assign the user of the jwt
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var id = int.Parse(identity.Claims.Where(c => c.Type == "id")
.Select(c => c.Value).SingleOrDefault());
bool isValidToken = IsValidToken(id, userName, type);
if (isValidToken == true)
{
status = "Success";
}
else
{
statusCode = HttpStatusCode.Unauthorized;
status = "Unauthorized";
}
}
catch (SecurityTokenValidationException e)
{
e.Message.ToString();
statusCode = HttpStatusCode.Unauthorized;
status = "Unauthorized";
}
catch (Exception ex)
{
ex.Message.ToString();
statusCode = HttpStatusCode.InternalServerError;
status = "InternalServerError";
}
return status;
}
public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
private bool IsValidToken(int? id, string userName, string type)
{
bool isValid = false;
using (MCSDEMOEntities con = new MCSDEMOEntities())
{
var GetUserDatails = (from u in con.ios_Users
where u.ID == id && u.LOGIN == userName && u.TYPEDESCR == type
select u).ToList();
if (GetUserDatails.Count == 1)
{
isValid = true;
}
else
{
isValid = false;
}
}
return isValid;
}
}
public static class HttpRequestHeadersExtensions
{
public static void Set(this HttpRequestHeaders headers, string name, string value)
{
if (headers.Contains(name)) headers.Remove(name);
headers.Add(name, value);
}
}
public static class HttpAuthenticationChallengeContextExtensions
{
public static void ChallengeWith(this HttpAuthenticationChallengeContext context, string scheme)
{
ChallengeWith(context, new AuthenticationHeaderValue(scheme));
}
public static void ChallengeWith(this HttpAuthenticationChallengeContext context, string scheme, string parameter)
{
ChallengeWith(context, new AuthenticationHeaderValue(scheme, parameter));
}
public static void ChallengeWith(this HttpAuthenticationChallengeContext context, AuthenticationHeaderValue challenge)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result);
}
}
public class AddChallengeOnUnauthorizedResult : IHttpActionResult
{
public AuthenticationHeaderValue Challenge { get; private set; }
public IHttpActionResult InnerHttpResult { get; private set; }
public AddChallengeOnUnauthorizedResult(AuthenticationHeaderValue challenge, IHttpActionResult innerResult)
{
Challenge = challenge;
InnerHttpResult = innerResult;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = await InnerHttpResult.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
// Only add one challenge per authentication scheme.
if (!response.Headers.WwwAuthenticate.Any((h) => h.Scheme == Challenge.Scheme))
{
response.Headers.WwwAuthenticate.Add(Challenge);
}
}
return response;
}
}
public class AuthenticationFailureResult : IHttpActionResult
{
public string ReasonPhrase { get; private set; }
public HttpRequestMessage Request { get; private set; }
public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(execute());
}
private HttpResponseMessage execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
response.ReasonPhrase = ReasonPhrase;
return response;
}
}
我的webapi config file
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
//check each request
config.Filters.Add(new HandleRequest());
// configuration for json reponse
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
//LoginController
// Login Model
config.Routes.MapHttpRoute(
name: "LoginApi",
routeTemplate: "{controller}/{action}",
defaults: new { controller = "Login", action = "UserLogin", id = RouteParameter.Optional }
);
}
和我的登录控制器
public class LoginController : ApiController
{
LoginModel logMod = new LoginModel();
LoginResponse logResp = new LoginResponse();
[HttpPost]
public LoginResponse UserLogin(LoginRequest logReq)
{
logResp = logMod.UserLogin(logReq );
return logResp;
}
}
登录模式class
public LoginResponse UserLogin(LoginRequest LogReq)
{
LoginResponse logResp = new LoginResponse();
try
{
if (LogReq.userName != "" && LogReq.password != "")
{
using (MCSDEMOEntities DataModel = new MCSDEMOEntities())
{
var UserDetails = (from user in DataModel.ios_Users
where (user.LOGIN == LogReq.userName && user.PASSWORD == LogReq.password && user.ACTIVE != 0)
select new
{
user.ID,
user.TYPEDESCR,
user.USERNAME
}).ToList();
if (UserDetails.Count != 0)
{
foreach (var Udetails in UserDetails)
{
logResp.id = Udetails.ID;
logResp.type = Udetails.TYPEDESCR;
logResp.userName = Udetails.USERNAME;
}
//create jwt token.
logResp.userToken = createToken(logResp.id, logResp.type, LogReq.userName);
logResp.Status = "Success";
}
else
{
logResp.Status = "401";
//throw new HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest);
// throw new AuthenticationFailureResult("","")
}
}
}
else
{
logResp.Status = "No Condition Match";
}
}
catch (Exception ex)
{
logResp.Status = ex.Message.ToString();
}
return logResp;
}
在上面的代码中,它很好地执行了服务,但即使用户 ID 和密码不匹配,它也会发送 http-200 ok 消息和我的状态 - json 中的 401。我想通过代码 401
传递 http您需要 return HttpResponseMessage
来自您的 api 以便您可以使用状态等其他信息包装您的响应对象
[HttpPost]
public HttpResponseMessage UserLogin(LoginRequest logReq)
{
logResp = logMod.UserLogin(logReq );
// Decide based on your logic. This is
// a mock example.
var status = HttpStatusCode.OK
return Request.CreateResponse(HttpStatusCode.OK, logResp);
}
您可以在此处找到更多信息:https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results
引自:
HttpResponseMessage Convert directly to an HTTP response
Other type Write the serialized return value into the response body; return 200 (OK).