自定义认证管理器,分为两级:1、登陆认证。2、权限认证。权限主要是用户、角色、角色用户关系、功能(系统资源)、角色功能关系,5部分决定用户的权限(视图)。
两层认证都通过后,更新session的最新交互时间,session有效期30分钟。
每个请求头部必须另加sessionID、token,加sessionID的目的是先根据ID加快检索,再和token对比,是否超时、退出等。
1 class WmsServiceAuthorizationManager : ServiceAuthorizationManager 2 { 3 protected override bool CheckAccessCore(OperationContext operationContext) 4 { 5 var via = operationContext.IncomingMessageProperties.Via; 6 var ctx = WebOperationContext.Current; 7 var id = ctx.IncomingRequest.Headers["id"]; 8 var token = ctx.IncomingRequest.Headers["token"]; 9 10 // 若不是登录接口 11 if (via.Segments.Count(x => x.ToLower().Equals("login") || x.ToLower().Equals("logout")) == 0) 12 { 13 long sessionId = 0; 14 if (!long.TryParse(id, out sessionId)) 15 { 16 // 若提供的sessionID无效,则登陆认证失败=401 17 ctx.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized; 18 return false; 19 } 20 // 若提供的ID 和 token无效,则登陆认证失败=401 21 var userSvc = new UserSvc(); 22 var session = userSvc.GetSession(sessionId, token);// session有效期30分钟无动作 23 if (session == null || session.logout_time != null 24 || session.user_id == null || session.update_time < DateTime.Now.AddMinutes(-30)) 25 { 26 ctx.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized; 27 return false; 28 } 29 userSvc.UpdSession(sessionId, token);// 更新最后一次交互时间 30 31 // 验证权限是否足够,否则禁止访问=403 32 var userAuths = userSvc.GetUserAuths(session.user_id.Value); 33 bool isAuth = via.Segments.Any(segment => userAuths.Count(x => x.fun_name.ToLower().Equals(segment.ToLower())) > 0); 34 if (!isAuth) 35 { 36 ctx.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden; 37 return false; 38 } 39 } 40 return true; 41 } 42 }
宿主绑定认证管理器:
1 static void Main(string[] args) 2 { 3 ServiceHost host = new ServiceHost(typeof(Wms.Service.WmsService)); 4 host.Authorization.ServiceAuthorizationManager = new WmsServiceAuthorizationManager(); 5 host.Open(); 6 Console.WriteLine("已启动"); 7 Console.WriteLine("回车键退出"); 8 Console.ReadLine(); 9 }
angular请求前统一添加令牌,和认证失败后重定向、及权限不足提示:
1 app.factory('interceptor', function ($q, $location) { 2 return { 3 request: function (config) { 4 if (config.url.indexOf('/login/') === -1 && sessionStorage.session) { 5 var session = JSON.parse(sessionStorage.session); 6 config.headers['id'] = session.id; 7 config.headers['token'] = session.token; 8 } 9 10 // 禁止HTML缓存 11 if(config.url.indexOf('.html') > 0){ 12 //var nocache = '?v=' + new Date().getTime(); 13 var idx = config.url.indexOf('?v='); 14 if(idx === -1) 15 config.url += appVersion; 16 else{ 17 config.url = config.url.substr(0, idx) + appVersion; 18 } 19 } 20 return config || $q.when(config); 21 }, 22 response: function (response) { 23 if (response.config.url.indexOf('service') > -1) { 24 //todo 预处理请求结果 25 } 26 return response || $q.when(response); 27 }, 28 responseError: function (response) { 29 if (response.status === 401) {// If our response status is unauthorized 30 sessionStorage.removeItem('session'); 31 layer.msg('认证失败,重新登录!'); 32 $location.path('/main/index');// Redirect to the login screen 33 }else if (response.status === 403) {// If our response status is Forbidden 34 layer.msg('认证失败,权限不足'); 35 }else { 36 return $q.reject(response);// Reject our response 37 } 38 } 39 }; 40 });
添加拦截器
1 $httpProvider.interceptors.push('interceptor');