【问题标题】:Authorize attribute is ignoring [AllowAnonymous]授权属性忽略 [AllowAnonymous]
【发布时间】:2014-10-16 18:30:24
【问题描述】:

我在我的 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] 属性应用于我的控制器操作,也会调用此类。

这给我的登录操作带来了麻烦,因为用户还没有令牌。

我该如何解决这个问题?

【问题讨论】:

  • 如果资源控制器/操作具有 [AllowAnonymous],您必须检查自定义属性内部。
  • @Fals 有什么建议吗?该信息是否包含在上下文中?

标签: c# asp.net-web-api authorization custom-attributes


【解决方案1】:

AllowAnonymous 仅适用于授权过滤器。您在这里拥有的是身份验证过滤器。请改用 System.Web.Http 中的OverrideAuthentication

更新

我在原始答案中的什么地方说过您必须实施身份验证?我所说的是,如果您不想调用TokenAuthenticationAuthenticateAsync 方法,请应用OverrideAuthentication,而不是AllowAnonymousAllowAnonymous 仅适用于授权过滤器,不适用于身份验证过滤器。因此,在您的 Login 操作中,您需要像这样应用 OverrideAuthentication

public class SomeController : ApiController
{
    [OverrideAuthentication]
    public HttpResponeMessage Login(Dto dto)
    { }
}

【讨论】:

  • 我很困惑,你说我有一个身份验证过滤器,但我必须实现身份验证?我没有这样做吗?你能详细说明一下吗?
猜你喜欢
  • 2013-11-09
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 1970-01-01
  • 2019-09-10
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
相关资源
最近更新 更多