SPA - Firebase和.Net Web Api 2身份验证

时间:2014-07-14 20:26:40

标签: javascript c# asp.net angularjs firebase

我有一个用AngularJs编写的单页面应用程序(此时框架无关紧要)应用程序托管在IIS中,它由index.html和一堆客户端资产组成。< / p>

在后端我有WebApi 2,也作为单独的应用程序在IIS中托管。

对于客户端身份验证我使用Firebase(简单登录)启用了多个社交网络,如Facebook,Twitter或Google。

到目前为止一切顺利。我喜欢用firebase启用twitter身份验证是多么容易。

在使用社交网络登录时,我从firebase返回,firebaseAuthToken和提供者accessstoken。

现在我想使用firebaseAuthToken或提供者访问令牌来验证我的WebApi。

问题是:在给定条件下使用WebApi进行身份验证的最佳方法是什么?

由于我在服务器上安装了复杂的业务逻辑,因此无法使用firebase来存储我的数据并摆脱web api。

到目前为止,我有一个愚蠢的想法是将社交提供者访问令牌传递给服务器,针对提供者验证令牌,然后使用Owin -Katana发布安全令牌。

由于缺乏文档,复杂性以及与单页应用程序的错误集成,我没有在katana中使用社交提供程序支持构建。我发现SPA的视觉工作室模板太具体了。但那就是我:)

1 个答案:

答案 0 :(得分:10)

tl; dr - Demo Project on GitHub

以下步骤可能看起来很长,但实际上非常简单。我在一个小时左右的时间内创建了我的演示项目。


我同意你关于使用Owin和Katana的看法。我以前经历过这个过程,并不是一次非常棒的经历。使用Firebase非常容易。

这一切都可以通过JWT完成!

当您通过Firebase和任何社交提供商进行身份验证时,您将获得JSON Web令牌(JWT) - firebaseAuthToken

从信息中心获取Firebase机密

JWT的工作方式是我们有一个秘密令牌和一个客户端令牌。客户端令牌是我们在登录后收到的firebaseAuthToken。在Firebase控制台中为我们生成了秘密令牌。

Firebase JWTs Dashboard

将您的Firebase机密存储在Web.config

的appSettings部分中

我们需要将此密钥存储在Web.config中,以便以后更容易访问。

<add key="FirebaseSecret" value="<Firebase-Secret-Token-Goes-Here" />

创建一个动作过滤器以检查授权标题中的JWT

我们可以通过在Authorization标头中传递客户端令牌来验证请求是否有效。在服务器上,我们可以存储从Firebase仪表板获取的密钥。当Web API检查请求时,我们可以使用JWT库(available from NuGet)解码JWT。如果解码成功,那么我们可以检查令牌以确保它没有过期。

public class DecodeJWT: ActionFilterAttribute 
{

    public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) 
    {
        string firebaseAuthToken = string.Empty;
        if (actionContext.Request.Headers.Authorization != null) {
            firebaseAuthToken = actionContext.Request.Headers.Authorization.Scheme;
        } else {
            throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized");
        }

        string secretKey = WebConfigurationManager.AppSettings["FirebaseSecret"];
        try {
            string jsonPayload = JWT.JsonWebToken.Decode(firebaseAuthToken, secretKey);
            DecodedToken decodedToken = JsonConvert.DeserializeObject < DecodedToken > (jsonPayload);
            // TODO: Check expiry of decoded token
        } catch (JWT.SignatureVerificationException jwtEx) {
            throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized");
        } catch (Exception ex) {
            throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized");
        }

        base.OnActionExecuting(actionContext);
    }

}

创建$ httpInterceptor将firebaseAuthToken添加到每个请求的标头

在客户端上,诀窍是必须每次都传递令牌。为方便起见,我们需要使用Angular创建$httpInterceptor,以检查firebaseAuthToken上的sessionStorage

.factory('authInterceptor', function ($rootScope, $q, $window) {
    return {
        request: function (config) {
            config.headers = config.headers || {};
            if ($window.sessionStorage.firebaseAuthToken) {
                config.headers.Authorization = $window.sessionStorage.firebaseAuthToken;
            }
            return config;
        },
        response: function (response) {
            if (response.status === 401) {
                // TODO: User is not authed
            }
            return response || $q.when(response);
        }
    };
})

在成功登录时将firebaseAuthToken设置为sessionStorage

每当用户登录时,我们都可以将值设置为sessionStorage

$rootScope.$on('$firebaseSimpleLogin:login',
    function (e, user) {

        // add a cookie for the auth token
        if (user) {
            $window.sessionStorage.firebaseAuthToken = user.firebaseAuthToken;
        }

        cb(e, user);
    });

全局注册DecodeJWT过滤器

WebApiConfig.cs Register方法的内部,我们可以设置DecodeJWT过滤器以应用于我们所有的ApiControllers。

config.Filters.Add(new DecodeJWT());

现在每当我们向ApiController发出请求时,它都会拒绝它,除非有一个有效的JWT。因此,在用户登录后,如果它已经不存在,我们可以将它们的数据保存到ApiController。

// globally uses DecodeJWT
public class UsersController: ApiController 
{
    // POST api/users
    public void Post([FromBody] FbUser user) // See GitHub for this Model
    {
        // Save user if we do not already have it
    }
}