我正在为Angular
SPA
(单页应用程序)编写代码。
在后端,它连接到用Java
编写的引擎,该引擎执行大部分处理(我不关心)。
我正在使用UI Router
进行路由。
问题
然而,我无法完成一个棘手的情况。
登录时,我会进行API调用,以JSON
格式返回响应。
如果我的呼叫成功(即登录凭证匹配)我在返回的JSON
中得到一个令牌,它基本上只是一个符号,字母和数字组合的字符串。
我将此保存在rootscope
中,然后以$ rootScope.myToken的形式访问它。
然后我在后续的API调用中使用相同的标记。
现在我想在AngularJS
中做的是将用户重定向到登录页面,如果他/她没有登录并尝试通过在地址栏中输入来直接访问某个URL。
我在这里找到了一个相当简单的方法Redirect on all routes to login if not authenticated。但是我无法用我的令牌实现这一点。
问题
如何使用令牌进行此操作?除了这个答案之外的任何其他建议也是受欢迎的。
PS:我在stackoverflow上尝试了多种方法,但我发现它们要么在我的上下文中不起作用,要么在过程中过于复杂。
更新:我可以在我的代码中成功实现 Simon H的答案。然而,我面临的问题是,这只会重新定向,因为我已经登录并退出我的应用程序至少一个。如果我尝试直接通过URL访问页面而不登录和注销至少一次,则此方法失败,我仍然可以访问该页面。有小费吗?
答案 0 :(得分:1)
网上有很多关于angular和jwt的教程
我用这些来开发你想要的东西。它们的关键部分是在配置
中$httpProvider.interceptors.push(function($q, $location, $localStorage, $injector) {
return {
'request': function (config) {
config.headers = config.headers || {};
if ($localStorage.token) {
config.headers.Authorization = 'Bearer ' + $localStorage.token;
}
return config;
},
'responseError': function(response) {
/* 401, unauthorised:
- bad username / password
- token expired
403, forbidden - notAdmin
*/
// if(response.status === 401 || response.status === 403) {
if(response.status === 401) {
console.log("app.js: httpInterceptor caught 40x:", response);
$injector.get('$state').go('login');
}
// Replace reponse with rejected promise to prevent rest of execution
return $q.reject(response);
}
};
答案 1 :(得分:0)
可能真的很晚(因为Angular2已经出来但是如果有人还在使用1.x我还在回答)但是我已经按照自己的时间使用Node发送JWT和Angular使用它而我用UI路由器做了。 然而,Simon的解决方案仍然有效,我尽量不要触摸rootScope。
我实现3个东西让它工作。授权服务,ngStorage模块和Ui路由器的状态解析属性。
<强> ngStorage 强>
这是一个公开$ localStorage和$ sessionStorage的模块。您可以向其添加任何对象,它将在浏览器中设置它,直到您清除它为止。
UI路由器状态的解决方案
1.x的官方文档声明,resolve是一个映射到函数的属性,在状态甚至初始化之前将触发。因此,这是一个你可以做一个国家依赖的微配置的地方,它也可以兑现承诺。
授权工厂
这是一家拥有3项服务的工厂。登录,注销和isAuthenticated。登录服务在成功时在$ localStorage中设置令牌。在它的依赖注入中,我使用ngStorage的$ localStorage服务以及$ http和其他服务注入它。
现在我解释一下我是如何做到的。
我总是将默认状态指向我的家乡状态,而不是登录状态。
我没有使用rootscope,而是将Authorization Factory的登录服务发布到服务器的登录端点(终点将给我一个新的令牌)。收到令牌后,我将其设置为$ localStorage作为我的令牌。
然后,在解决我的家庭状态时,我调用授权工厂的isAuthenticated服务,它只检查令牌是否在$ localStorage中设置。如果不是,则返回false。如果它返回false,我可以通过$ state.go('login')转换home state重定向到我的登录状态;
我得到的是,在每个$ http呼叫应用程序范围内,我可以在控制器中注入Authorization的isAuthenticated服务并让它检查令牌(获得哪个登录服务以及isAuthenticated也可以访问,因为它们是在同一家工厂)。如果令牌存在,我提取该令牌并将其与我的数据一起发送到服务器。然后,我的服务器可以执行额外的令牌验证,例如检查它的到期时间和内容以及401s或200s的响应。
现在这可能听起来令人气愤,似乎并不是干涩的。但是我想说我在一个根父状态中做了所有这些,并将所有其他状态作为子状态附加。父是抽象的,因此可以做出决定,并且不需要初始化状态。家庭可以是默认的非抽象状态。
我试图远离rootScopes和$ watch和东西,我总是将它们作为最后的手段。干杯!