angular auth - meetbill/butterfly-fe GitHub Wiki
(1) 加载 js 文件,默认已加载
文件:templates/index.html
<!-- jwt -->
<script src="static/vendor/angular/angularJwt/services/authManager.js"></script>
<script src="static/vendor/angular/angularJwt/services/interceptor.js"></script>
<script src="static/vendor/angular/angularJwt/services/jwt.js"></script>
<script src="static/vendor/angular/angularJwt/services/jwtOptions.js"></script>
<script src="static/vendor/angular/angularJwt/services/urlUtils.js"></script>
<script src="static/vendor/angular/angularJwt/angularJwt.js"></script>
(2) 依赖注入,默认已注入
文件:static/js/app.js
angular.module('app', [
'...',
'angular-jwt'
]);
使用此模块,需要知道如何在本地获取 token,登录失败时如何操作,获取 token 中的信息
文件:config.js---- 拦截器及相关配置
.config(['$httpProvider','jwtOptionsProvider',function($httpProvider, jwtOptionsProvider) {
// Please note we're annotating the function so that the $injector works when the file is minified
jwtOptionsProvider.config({
// 配置如何在本地获取 token
//------------------------------------------------------ 从本地 $localStorage 获取
tokenGetter: ['$localStorage',function($localStorage) {
return $localStorage.jwt;
}],
//------------------------------------------------------ 从 cookie 中获取
tokenGetter: ['$cookies',function($cookies) {
return $cookies.get("butterfly_token");
}],
// 认证失败时,则进行跳转到 "access.signin"
unauthenticatedRedirector: ['$state', function($state) {
$state.go('access.signin');
}],
// 发送请求时携带的 token 前缀
authPrefix: 'Bearer: '
});
$httpProvider.interceptors.push('jwtInterceptor');
}])文件:config.router.js 订阅特定事件
angular.module('app')
.run(
[ '$rootScope', '$state', '$stateParams', 'authManager',
function ($rootScope, $state, $stateParams, authManager) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
// 如下为新增内容
// 切换路由时等都会进行校验 token
authManager.checkAuthOnRefresh();
// 认证失败时,进行跳转到普通登录页面
authManager.redirectWhenUnauthenticated()
// 认证失败时,进行跳转到单点登录特定页面(需要跳转的页面由 401 页面中返回)
authManager.redirectWhenUnauthenticatedSSO()
}
]
)
获取 username
在 static/vendor/angular/angularJwt/services/authManager.js 中设置了当路由刷新时进行重新校验 token,同时进行获取用户名
decode_token = jwtHelper.decodeToken(token);
$rootScope.username = decode_token.username;
在 UI 中可以直接通过 __username__ 获取用户名
<span class="hidden-sm hidden-md">__username__</span>
监听到 "unauthenticated" 事件,进行跳转到站内登录路由
文件:config.router.js
authManager.redirectWhenUnauthenticated()
如果认证使用的 "单点登录 SSO", 则监听到 "unauthenticated" 事件,进行跳转到站外登录接口
文件:config.router.js
authManager.redirectWhenUnauthenticatedSSO()
使用 authManager 管理身份验证状态的
authmanager
{
authenticate: authenticate, // 设置 $rootScope.isAuthenticated = true;
unauthenticate: unauthenticate, // 设置 $rootScope.isAuthenticated = false;
getToken: function(){ return invokeToken(config.tokenGetter); },// 获取 token
redirect: function() { return invokeRedirector(config.unauthenticatedRedirector); }, // 重定向位置
checkAuthOnRefresh: checkAuthOnRefresh, // 在页面刷新时获取身份验证状态
redirectWhenUnauthenticated: redirectWhenUnauthenticated, // 如果有接口返回 401 ,重定向到登录页面
isAuthenticated: isAuthenticated, // 获取 $rootScope.isAuthenticated 状态
redirectWhenUnauthenticatedSSO: redirectWhenUnauthenticatedSSO, // 单点登录跳转
}
发布 ----- 注册拦截器 angularJwt/services/interceptor.js
angular.module('angular-jwt.interceptor', [])
.provider('jwtInterceptor', function() {
return {
request: function(config) {
// do something on request success
// 此处将所有请求添加了 jwt header
},
requestError: function(rejection) {
// do something on request error
},
response: function(response) {
// do something on response success
},
responseError: function(rejection) {
// do something on response error , 这的 $broadcast 就是进行发布事件
// 例子:$scope.$broadcast('EVENT_NAME', 'Data to send');
if (response !== undefined && response.status === 401) {
$rootScope.$broadcast('unauthenticated', response);
}
return $q.reject(response);
}
};订阅之开启:config.router.js
angular.module('app')
.run(
[ '$rootScope', '$state', '$stateParams', 'authManager',
function ($rootScope, $state, $stateParams, authManager) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
// 如下为新增内容
// 检查是否 jwt token 是否已过期
authManager.checkAuthOnRefresh();
// 开启订阅 'unauthenticated' 事件,然后决定是否进行跳转等操作
authManager.redirectWhenUnauthenticated()
// 开启订阅 'unauthenticated' 事件,进行单点登录操作,跳转到站外登录接口
authManager.redirectWhenUnauthenticatedSSO()
}
]
)订阅之事件处理
跳转站内登录接口
function redirectWhenUnauthenticated() {
$rootScope.$on('unauthenticated', function () {
invokeRedirector(config.unauthenticatedRedirector);
unauthenticate();
});
}跳转站外登录接口
function redirectWhenUnauthenticatedSSO() {
$rootScope.$on('unauthenticated', function (event,response) {
unauthenticate();
target_url = response.data.data.redirect;
$window.location.href = target_url;
});
}
angular/angularJwt/services/interceptor.js
拦截器检查 responseError 时,则发布 'unauthenticated' 事件
权限的设计中比较常见的就是 RBAC 基于角色的访问控制,基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。
在 Angular 构建的单页面应用中,要实现这样的架构我们需要额外多做一些事。从整体项目上来讲,大约有 3 处地方,前端工程师需要进行处理。
(1) UI 处理(根据用户拥有的权限,判断页面上的一些内容是否显示)
(2) 路由处理(当用户访问一个它没有权限访问的 url 时,跳转到一个错误提示的页面)
(3) HTTP 请求处理(当我们发送一个数据请求,如果返回的 status 是 401 或者 401, 则通常重定向到一个错误提示的页面)
对应 Angulr
UI 处理 ------------> static/tpl/blocks/nav.html 根据角色展示不同的页面
HTTP 请求处理 ------> angular-jwt 认证部分
UI 处理
角色与导航关系存储在前端
用户认证成功后,后端返回给前端此用户的角色
前端根据此用户的角色更新 static/tpl/blocks/nav.html
https://github.com/auth0-blog/angularjs-jwt-authentication-tutorial
这个 angularjs-jwt-authentication-tutorial 使用的是旧版本的 angular-jwt ,Provider 和 变量等都改过名字,所以仅供参考下
https://github.com/thuslako/Portfolio-/blob/92d017a035363b690120d6a2ebbf45ff6a16116f/public/libs/angular-jwt/README.md