我已经在asp.net Web API中设置了客户授权属性
全局文件:
FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
FilterConfig.cs
public static void RegisterHttpFilters(System.Web.Http.Filters.HttpFilterCollection filters)
{
filters.Add(new TokenAuthentication(""));
}
认证类别:
public class TokenAuthentication : Attribute, IAuthenticationFilter
{
private readonly string realm;
public bool AllowMultiple { get { return false; } }
public TokenAuthentication(string realm)
{
this.realm = "realm=" + realm;
}
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var request = context.Request;
// Receive token from the client. Here is the example when token is in header:
string token = null;
if (request.Headers.Contains("Token"))
{
token = request.Headers.GetValues("Token").FirstOrDefault();
}
if (token != null && token != "")
{
// Get your secret key from the configuration
var secretKey = ConfigurationManager.AppSettings["JWTSecurityKey"];
try
{
//Get the Payload from the token
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey);
int separatorIndex = jsonPayload.IndexOf(';');
string userId = "";
DateTime timeIssued = DateTime.MinValue;
if (separatorIndex >= 0)
{
//userId = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(jsonPayload.Substring(0, separatorIndex)));
userId = jsonPayload.Substring(1, separatorIndex - 1);
string tmpTime = jsonPayload.Substring(separatorIndex + 1, (jsonPayload.Length - separatorIndex) - 2);
timeIssued = DateTime.Parse(tmpTime);
}
short TokenTTL = 10; //minuets
//Int16.TryParse(ConfigurationManager.AppSettings["TokenTTL"],TokenTTL);
// if ((DateTime.Now.Subtract(timeIssued).TotalMinutes >= TokenTTL))
if ((DateTime.Now.Subtract(timeIssued).TotalMinutes < 0))
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
else
{
//Save user in context
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, userId)
};
var id = new ClaimsIdentity(claims, "Basic");
var principal = new ClaimsPrincipal(new[] { id });
// Set the user name to the user id in the httpcontext which is passed to the controller
context.Principal = principal;
}
}
catch (JWT.SignatureVerificationException)
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
}
else
{
return Task.FromResult(0);
}
return Task.FromResult(0);
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
context.Result = new ResultWithChallenge(context.Result, realm);
return Task.FromResult(0);
}
}
/// <summary>
///
/// </summary>
public class ResultWithChallenge : IHttpActionResult
{
private readonly IHttpActionResult next;
private readonly string realm;
/// <summary>
/// Constructor
/// </summary>
/// <param name="next"></param>
/// <param name="realm"></param>
public ResultWithChallenge(IHttpActionResult next, string realm)
{
this.next = next;
this.realm = realm;
}
/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var res = await next.ExecuteAsync(cancellationToken);
if (res.StatusCode == HttpStatusCode.Unauthorized)
{
res.Headers.WwwAuthenticate.Add(
new AuthenticationHeaderValue("Basic", this.realm));
}
return res;
}
}
现在我的问题是,即使将
[AllowAnonymous]
属性应用于我的Controllers Action,也要调用此类。由于用户还没有令牌,这给我带来了登录操作的麻烦。
我该如何纠正?
最佳答案
AllowAnonymous
仅适用于授权过滤器。您在这里拥有一个身份验证筛选器。请改用System.Web.Http中的OverrideAuthentication
。
更新
我在原始答案中说过必须执行身份验证的地方?我只是说,如果您不希望调用AuthenticateAsync
的TokenAuthentication
方法,请应用OverrideAuthentication
而不是AllowAnonymous
。 AllowAnonymous
仅适用于身份验证过滤器,不适用于身份验证过滤器。因此,在您的Login
动作中,您将需要像这样应用OverrideAuthentication
。
public class SomeController : ApiController
{
[OverrideAuthentication]
public HttpResponeMessage Login(Dto dto)
{ }
}