使用ASP.NET Web API进行跨平台认证

50

我该如何开始使用ASP.NET Web API编写跨平台的身份验证功能,以支持桌面、移动和Web?我读到有一些实现RESTful身份验证的方法,比如在请求头中使用令牌。

是否有任何示例项目使用了这种方法?

问题:

  1. 如果没有,如何修复[Authorize]属性以读取令牌?
  2. 如何生成这个令牌?我认为我不能使用FormAuthentication,因为那使用了cookie。
  3. 如何处理实际的授权,客户端发送原始密码和用户名然后我生成令牌,还是有其他方式?
  4. 当我的网站在使用时,我该如何处理它?我听说这与应用程序使用不同,例如获取域并进行授权。
4个回答

41

我认为令牌是一个可靠的方案。对于Web应用程序,基于表单的身份验证是基于Cookie的。但这不适用于所有非浏览器客户端。

我的建议是创建自定义AuthorizationFilterAttribute并重写OnAuthorization方法。在该方法中,您可以检查客户端是否存在您发放的令牌,以在他们提供有效凭据后进行验证。您可以在任何需要验证的方法或控制器上使用此属性。以下是一个示例供您参考

 public class AuthorizeTokenAttribute : AuthorizationFilterAttribute 
{      
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (actionContext != null)
        {                
                if (!AuthorizeRequest(actionContext.ControllerContext.Request))
                {
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { RequestMessage = actionContext.ControllerContext.Request }; 
                }
                return;
        }
    }

    private bool AuthorizeRequest(System.Net.Http.HttpRequestMessage request)
    {
        bool authorized = false;
        if (request.Headers.Contains(Constants.TOKEN_HEADER))
        {               
            var tokenValue = request.Headers.GetValues("TOKEN_HEADER");
            if (tokenValue.Count() == 1) {
                var value = tokenValue.FirstOrDefault();               
               //Token validation logic here
               //set authorized variable accordingly
            }                
        }
        return authorized;
    } }

TOKEN_HEADER是一个表示客户端应该在经过身份验证的请求中返回的HTTP标头字符串。

让我们一步步来:

  1. 客户端请求安全数据
  2. 客户端未获授权,返回带有未经授权状态代码的响应
  3. 客户端发送凭据进行身份验证,这应该通过HTTPS进行保护
  4. 验证后,客户端通过HTTP标头或其他适合您的方式接收令牌
  5. 客户端再次尝试请求安全数据,这次将令牌附加到请求中
  6. AuthorizeTokenAttribute将验证令牌并允许执行操作。

此外,请查看John Petersen发布的文章。 使ASP.NET Web API安全


1
谢谢,这很有帮助。您如何建议在身份验证期间生成令牌?生成一个GUID并将其存储到数据库中供用户使用? - Shawn Mclean
2
还可以查看John Petersen的更新帖子,他在其中使用Http消息处理程序而不是Action过滤器http://codebetter.com/johnvpetersen/2012/04/04/moving-from-action-filters-to-message-handlers/。 - shashi
1
API应该有一些端点,允许进行身份验证/授权工作流程。就像网站有登录页面一样。 - cecilphillip
@ray247 你真的建议在授权之后进行身份验证吗? - Elisabeth
我喜欢使用 Constants.TOKEN_HEADER 来检查值是否在标头中,但是要检索该值时,使用字符串常量 "TOKEN_HEADER"。 - Robinhopok
显示剩余5条评论

21

有很多方法可以为REST服务验证用户。使用令牌是可能的,但只使用基本身份验证甚至更简单,而且几乎是标准和跨平台的。

不要混淆授权身份验证。[Authorize]属性完全关于授权,但仅在使用其他机制对用户进行身份验证后才能进行。没有进行适当的身份验证,授权是完全无用的。

检查最佳资源的人是Dominick Baier,他是该主题的专家。


对于基本身份验证,这是正确的方法。使用HTTPS,因为编码只是base64,而不是加密。 - Maurice
Dominick Baier的文章链接已经失效。 - Josh Noe

2
我使用非常简单的方法:
  1. 定义一个访问配置文件,其中包含唯一的accessId和accessKey(例如,MD5哈希的GUID值)
  2. 将此类访问配置文件存储在数据库中
  3. 每个请求(GET / POST /等)必须提供accessId、queryHash(表示查询的MD5哈希值)和signature(queryHash + accessKey的MD5哈希值)。当然,客户端需要将accessKey保存在一个安全的地方!!!
  4. 服务器收到请求后,将使用相同的计算算法检查accessId和signature,以拒绝或授予访问权限(进行身份验证)
  5. 可以基于请求类型使用访问配置文件进一步进行授权
这种方法的服务使用新的ASP.NET MVC Web API可以为任何类型的客户端提供服务:浏览器/JavaScript和本机(桌面或移动设备)等。

3
你可能需要考虑比MD5更强的加密算法。目前,它可以很快被破解,只需要几分钟或几个小时。你应该使用一些更强的哈希算法,比如SHA256/512,或者更好的选择是一些计算上慢的算法,比如bCrypt。 - EBarr
这是一些有用的信息@EBarr(我+1了你),但考虑到他加密的内容太大且模糊不清,无法使用彩虹表,所以我认为在这种情况下使用MD5会更安全。 - Grinn
@Grinn 彩虹表早在2005年就过时了;-)。当然,MD5可能做到了。但是,现在强大的GPU可以在几分钟内对MD5进行暴力破解。例如,亚马逊EC2 GPU盒子只需花费几美元。 - EBarr

0

您可以使用ActionFilterAttribute并重写OnActionExecuting方法。然后在global.cs中注册此过滤器,以便在Application Start方法中像这样应用此过滤器来适用于所有操作:

var config = GlobalConfiguration.Configuration; config.Filters.Add(new CustomAuthAttribute ());

{ namespace Customss { Public class CustomAuthAttribute : ActionFilterAttribute

{

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        // To inforce HTTPS if desired , else comment out the code
        if (!String.Equals(actionContext.Request.RequestUri.Scheme, "https", StringComparison.OrdinalIgnoreCase))
        {
            actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
            {
                Content = new StringContent("HTTPS Required")
            };
            return;
        }

       // get toekn from the header

        var userToken = actionContext.Request.Headers.GetValues("UserToken");
         // Customer Logic to check the validity of the token.
        // U can have some DB logic to check , custom STS behind or some loca cache used to compare the values


    }


}

} }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接