我有一个用AngularJs编写的单页应用程序(此时框架无关紧要)该应用程序托管在IIS中,它由index. html和一堆客户端资产组成。
在后端,我有WebApi 2,也作为单独的应用程序托管在IIS中。
对于客户端的身份验证,我使用Firebase(简单登录)并启用了多个社交网络,如Facebook、Twitter或Google。
到目前为止还不错。我喜欢启用twitter身份验证的简单性,例如使用Firebase。
在使用社交网络登录时,我从Firebase、FirebaseAuthToken和提供商访问返回。
现在我想使用fire baseAuthToken或提供者访问令牌来使用我的WebApi进行身份验证。
问题是:在给定条件下使用WebApi进行身份验证的最佳方式是什么?
由于我在服务器上放置了复杂的业务逻辑,因此无法仅使用Firebase来存储我的数据并摆脱Web API。
到目前为止,我有一个愚蠢的想法,就是将社交提供者访问令牌传递给服务器,针对提供者验证令牌,然后使用Owin-Katana颁发安全令牌。
由于缺乏留档、复杂性和与单页应用程序的糟糕集成,我没有使用katana的内置社交提供商支持。我发现SPA的Visual Studio模板过于MVC特定。但那是我:)
下面的步骤可能看起来很长,但实际上非常简单。我在一个小时左右的时间里创建了我的演示项目。
我同意你关于使用Owin和Katana的观点。我以前经历过这个过程,这不是一个很好的体验。使用Firebase要容易得多。
这一切都可以用JWT来完成!
当您通过Firebase和任何社交提供商进行身份验证时,您会得到一个JSONWeb令牌(JWT)-fire baseAuthToken
。
JWT的工作方式是我们有一个秘密令牌和一个客户端令牌。客户端令牌是我们登录后收到的FirebaseAuthToken。秘密令牌是在Firebase仪表板中为我们生成的。
我们需要将此密钥存储在Web. config中,以便以后更容易访问。
<add key="FirebaseSecret" value="<Firebase-Secret-Token-Goes-Here" />
我们可以通过在授权标头中传递客户端令牌来验证请求是否有效。在服务器上,我们可以存储从Firebase仪表板获得的密钥。当WebAPI检查请求时,我们可以使用JWT库(可从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);
}
}
在客户端上,诀窍是每次都必须传递令牌。为了使这更容易,我们需要使用Angular创建一个$httpInterceptor
,用于检查session sionStorage
上的fire baseAuthToken
。
.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);
}
};
})
每当用户登录时,我们都可以将值设置为session sionStorage
。
$rootScope.$on('$firebaseSimpleLogin:login',
function (e, user) {
// add a cookie for the auth token
if (user) {
$window.sessionStorage.firebaseAuthToken = user.firebaseAuthToken;
}
cb(e, user);
});
在WebApiConfig. cs
注册方法中,我们可以设置DecodeJWT过滤器以应用于我们所有的ApiController。
config.Filters.Add(new DecodeJWT());
现在,每当我们向ApiController发出请求时,它都会拒绝它,除非有有效的JWT。因此,在用户登录后,如果ApiController不存在,我们可以将他们的数据保存到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
}
}