• asp.net web api 授权功能


    1、重写授权方法

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using System.Web.Security;
    using WebAPI.Models;
    using WebAPI.Toolkit;
    
    namespace WebAPI.Filter
    {
        /// <summary>
        /// 授权
        /// </summary>
        public class RequestAuthorizeAttribute:AuthorizeAttribute
        {
            /// <summary>
            /// 重写授权方法,加入自定义的Ticket验证
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                var isActionAnonymous = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>().Any(a => a is AllowAnonymousAttribute);
                var isControllerAnonymous = actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>().Any(a => a is AllowAnonymousAttribute);
    
                //如果控制器和动作上允许匿名访问
                if (isControllerAnonymous || isActionAnonymous)
                {
                    base.OnAuthorization(actionContext);
                }
                else
                {
                    //从http请求的头里面获取身份验证信息,验证是否是请求发起方的ticket
                    var headers = actionContext.Request.Headers;
                    if ((headers.Authorization != null) && (headers.Authorization.Parameter != null))
                    {
                        //解密用户ticket,并校验用户名密码是否匹配
                        if (ValidateTicket(headers))
                        {
                            base.IsAuthorized(actionContext);
                        }
                        else
                        {
                            HandleUnauthorizedRequest(actionContext);
                        }
                    }
                    else
                    {
                        HandleUnauthorizedRequest(actionContext);
                    }
                }
            }
    
            /// <summary>
            /// 校验用户身份
            /// </summary>
            /// <param name="headers">请求头</param>
            /// <returns></returns>
            private bool ValidateTicket(HttpRequestHeaders headers)
            {
                //解密Ticket
                var strTicket = FormsAuthentication.Decrypt(headers.Authorization.Parameter).UserData;
    
                //从Ticket里面获取用户名和密码
                var index = strTicket.IndexOf("&");
                string userName = strTicket.Substring(0, index);
                //string password = strTicket.Substring(index + 1);
    
                //获取令牌
                var token = headers.GetValues("AppId").FirstOrDefault();
                
                //根据令牌和用户名得到键
                string key = string.Format("{0}_{1}", token, userName);
    
                //根据缓存键拿到用户信息
                var userInfo = CacheHelper.GetCache(key);
                if (userInfo==null)
                {
                    return false;
                }
                return true;
            }
    
            /// <summary>
            /// 重写授权失败响应
            /// </summary>
            /// <param name="actionContext"></param>
            protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
            {
                base.HandleUnauthorizedRequest(actionContext);
    
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, new ResultModel { Status = false, Data = null, ErrorMessage = "您没有权限访问资源" });
            }
    
    
        }
    }

    2、基类控制器添加授权特性

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using WebAPI.Filter;
    using System.IO;
    using WebAPI.Models;
    using System.Text;
    using WebAPI.Toolkit;
    
    namespace WebAPI.Controllers
    {
        /// <summary>
        /// 接口基类
        /// </summary>
        [Result]
        [RequestAuthorize]
        public class BaseApiController : ApiController
        {
            /// <summary>
            /// 接口令牌
            /// </summary>
            protected string _token;
            /// <summary>
            /// 
            /// </summary>
            protected ApiClient _client;
            /// <summary>
            /// 接口配置
            /// </summary>
            public List<ApiModel> Apis
            {
                get
                {
                    string path = string.Format("{0}/config.json", AppDomain.CurrentDomain.BaseDirectory);
                    string result = "";
                    if (File.Exists(path))
                    {
                        result = File.ReadAllText(path);
                    }
                    return JsonConvert.DeserializeObject<List<ApiModel>>(result);
                }
            }
    
            /// <summary>
            /// 重写接口执行方法
            /// </summary>
            /// <param name="controllerContext">控制器上下文</param>
            /// <param name="cancellationToken"></param>
            /// <returns></returns>
            public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext,CancellationToken cancellationToken)
            {
                try
                {
                    var header = controllerContext.Request.Headers;
                    _token = header.GetValues("AppId").FirstOrDefault();//接口令牌
                    string baseAddress = Apis.FirstOrDefault(a => a.Id == _token).Url;
    
                    _client = new ApiClient(baseAddress, _token, header);
                }
                catch 
                {
                    var response = new HttpResponseMessage(HttpStatusCode.OK);
                    response.Content = new StringContent(JsonConvert.SerializeObject(new ResultModel() { ErrorMessage = "未经授权" }), Encoding.UTF8, "application/json");
    
                    var source = new TaskCompletionSource<HttpResponseMessage>();
                    source.SetResult(response);
                    return source.Task;
                }
                return base.ExecuteAsync(controllerContext, cancellationToken);
            }
    
        }
    }

    3.登录

    using AppViewModel;
    using AppViewModel.System;
    using System;
    using System.Collections.Generic;
    using System.Dynamic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web;
    using System.Web.Http;
    using System.Web.Security;
    using WebAPI.Models;
    using WebAPI.Toolkit;
    
    namespace WebAPI.Controllers.System
    {
        /// <summary>
        /// 用户信息
        /// </summary>
        public class UserController : BaseApiController
        {
            #region 登录
            
            /// <summary>
            /// 登录
            /// </summary>
            /// <param name="viewModel">登录实体</param>
            /// <returns></returns>
            [HttpPost]
            [AllowAnonymous]
            public UserViewModel Login([FromBody]LoginViewModel viewModel)
            {
                var result = _client.Post(viewModel, "api/SysUser/Login");
    
                string ticket = string.Empty;
                string key = string.Format("{0}_{1}", _token, viewModel.UserName);
    
                var userTicket = CacheHelper.GetCache(key);
                if (userTicket == null)
                {
                    //生成票据,通常是对用户名和密码进行编码,此处通过用户名和用户名编码进行混淆
                    var formTicket = new FormsAuthenticationTicket(0, viewModel.UserName, DateTime.Now, DateTime.Now.AddHours(8), true, string.Format("{0}&{1}", viewModel.UserName, viewModel.UserName), FormsAuthentication.FormsCookiePath);
                    //对票据进行加密
                    ticket = FormsAuthentication.Encrypt(formTicket);
                    CacheHelper.SetCache(key, ticket, DateTime.Now.AddHours(8));
                }
                else
                {
                    ticket = userTicket.ToString();
                }
    
                var userModel = new UserViewModel
                {
                    Id = result.Data.Id,
                    OrgId = result.Data.所属机构Id,
                    Name = result.Data.真实姓名,
                    Account = result.Data.用户名,
                    Token = ticket
                };
    
                //获取App用户主题
                var userTheme = _client.Get(string.Format("api/SysUserClientConfig/GetByUid?Uid={0}", userModel.Id));
                userModel.ThemeName = (userTheme.Data == null) ? "" : userTheme.Data.ThemeName;
    
                GetUserPosts(userModel);
    
                GetUserModules(userModel);
    
                return userModel;
            }
    
            /// <summary>
            /// 获取用户岗位列表
            /// </summary>
            /// <param name="userModel"></param>
            private void GetUserPosts(UserViewModel userModel)
            {
                var postResult = _client.Get(string.Format("api/SysBasicPost/GetByUid?Uid={0}", userModel.Id));
                if (postResult.Data == null)
                {
                    return;
                }
                foreach (var item in postResult.Data)
                {
                    userModel.UserPosts.Add(new PostViewModel() { Id = item.Id, Name = item.岗位名称 });
                }
            }
    
            /// <summary>
            /// 获取用户模块列表
            /// </summary>
            /// <param name="userModel"></param>
            private void GetUserModules(UserViewModel userModel)
            {
                if (userModel.UserPosts.Count < 1 || userModel.UserPosts.Count > 1)
                {
                    return;
                }
    
                //默认如果当前用户只有一个岗位就加载用户的模块列表
                var result = _client.Get(string.Format("api/SysModule/Get?Gid={0}&Uid={1}&Pid={2}", userModel.OrgId, userModel.Id, userModel.UserPosts.FirstOrDefault().Id));
                if (result.Data == null)
                {
                    return;
                }
    
                var viewModels = new List<ModuleViewModel>();
                foreach (var item in result.Data)
                {
                    viewModels.Add(new ModuleViewModel()
                    {
                        Id = item.Id,
                        PId = item.Pid,
                        Name = item.别名,
                        Url = item.默认入口页面,
                        IconUrl = item.图标URL
                    });
                }
    
                userModel.UserModules = viewModels.Where(a => a.PId == null).ToList();
                if (userModel.UserModules == null || userModel.UserModules.Count < 1)
                {
                    return;
                }
    
                //包装模块列表
                foreach (var item in userModel.UserModules)
                {
                    item.Childs = viewModels.Where(a => a.PId == item.Id).ToList();
                }
            }
    
            #endregion
    
            /// <summary>
            /// 获取用户列表
            /// </summary>
            /// <param name="queryModel">机构Id、岗位Id</param>
            /// <returns></returns>
            [HttpPost]
            public List<UserViewModel> GetUsers([FromBody]QueryBaseModel queryModel)
            {
                var result = _client.Get(string.Format("api/SysUser/GetByGidAndPid?Gid={0}&Pid={1}", queryModel.OrgId, queryModel.PostId));
                if (result.Data==null)
                {
                    return null;
                }
    
                var viewModels = new List<UserViewModel>();
                foreach (var item in result.Data)
                {
                    viewModels.Add(new UserViewModel(){ Id = item.Id, Name = item.真实姓名 });
                }
                return viewModels;
            }
    
            /// <summary>
            /// 获取用户详情
            /// </summary>
            /// <param name="userId">用户Id</param>
            /// <returns></returns>
            [HttpPost]
            public UserViewModel GetUserInfo([FromBody]int userId)
            {
                var result = _client.Get(string.Format("api/SysUser/GetById?Id={0}", userId));
                if (result.Data == null)
                {
                    return null;
                }
    
                var viewModel = new UserViewModel()
                {
                    Id = result.Data.Id,
                    Name = result.Data.真实姓名,
                    Tel = result.Data.手机,
                    Sex = result.Data.性别,
                    Email = result.Data.Email
                };
                return viewModel;
            }
    
    
        }
    }

    登录参考基础认证的方式,但是为了和网上基础认证做区别没有对用户名和密码进行加密,而是针对用户名和用户名进行加密,加密的核心我认为是打破常规为原则。

    如果某个接口不需要授权,则控制器或动作上方添加 [AllowAnonymous] 特性。

    注意点:如果重写授权方法没有处理好匿名特性的逻辑,会导致不该认证的接口,打上匿名特性也照样走认证流程。

  • 相关阅读:
    [整理III]微软等数据结构+算法面试100题[最新第61-80题]
    横空出世,席卷互联网--评微软等公司数据结构+算法面试100题
    SQL Server2008创建约束图解
    sqlserver2008中如何用右键可视化的设置外键
    SQL的主键和外键约束
    Visual Basic|VB 6.0中文版
    java 用eclipse j2ee写的servlet 程序,WEB-INF下的配置文件web.xml在哪啊?谢谢!
    SQL Server数据的导入导出
    MySQL命令行导出数据库
    VS2010数据库连接问题
  • 原文地址:https://www.cnblogs.com/wgx0428/p/9935605.html
Copyright © 2020-2023  润新知