@xuxuzhaozhao
2017-12-21T08:19:49.000000Z
字数 6417
阅读 545
webapi
AspNet WebApi 前后端分离,由于以后的ERP项目都将采用单页模式,索性完成前后端分离,其中最重要的就是授权相关的与之前采用Forms授权不同.
现在的授权模式将采用OWIN OAuth的方式,前台将登录获取token,然后将token放置在请求头.
1、使用Nuget包管理器安装稳定的最新的如下包:
1. Microsoft.AspNet.WebApi.Owin;2. Microsoft.Owin.Host.SystemWeb;3. Microsoft.AspNet.Identity.Owin;4. Microsoft.Owin.Cors;
2、在webapi项目的根文件夹下创建OWIN Startup类
using Microsoft.Owin;using Microsoft.Owin.Security.OAuth;using Owin;using System;using System.Web.Http;[assembly: OwinStartup(typeof(WebApi令牌身份验证.Startup))]namespace WebApi令牌身份验证{public class Startup{public void Configuration(IAppBuilder app){HttpConfiguration config = new HttpConfiguration();ConfigureOAuth(app);WebApiConfig.Register(config);app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);app.UseWebApi(config);}public void ConfigureOAuth(IAppBuilder app){OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions(){AllowInsecureHttp = true,TokenEndpointPath = new PathString("/token"),AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),Provider = new SimpleAuthorizationServerProvider()};app.UseOAuthAuthorizationServer(OAuthServerOptions);app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());}}}
3、根目录中新建Providers文件夹=>新建AuthorizationServerProvider.cs
using Microsoft.Owin.Security.OAuth;using System.Security.Claims;using System.Threading.Tasks;using YiCheng.Common.DAL;namespace YiCheng.Web.Api.Providers{/// <summary>/// 授权access_token/// </summary>public class YAuthorizationServerProvider : OAuthAuthorizationServerProvider{public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context){context.Validated();}/// <summary>/// 返回Token令牌/// </summary>/// <param name="context"></param>/// <returns></returns>public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context){context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });//验证码(暂未实现)//var validateCode = context.Scope[0];//对用户名、密码进行数据校验var sql = $"SELECT COUNT(1) FROM 用户表 WHERE 账号 = @用户名 AND 密码 = @密码;";var result = YDBHelper.ExecuteScalar2(sql, new{用户名 = context.UserName,密码 = context.Password}).ToString();if (int.Parse(result) <= 0){context.SetError("登录错误.", "用户名或者密码错误!");return;}var identity = new ClaimsIdentity(context.Options.AuthenticationType);identity.AddClaim(new Claim("yuser", context.UserName));context.Validated(identity);}}}
4、根目录中新建Filters文件夹=>新建YAuthorizeFilterAttribute.cs
继承AuthorizeAttribute,重写其中的授权方法,及对应的处理未授权的方法
//=====================================================// Copyright © 2017-2018 xuxuzhaozhao// All rights reserved// GUID: 7b80855a-8d31-4dc1-b9b7-72a5b2d29536// CLR版本: 4.0.30319.42000// 新建项输入的名称: AxuzerFilter// 机器名称: WIN10-20170502F// 当前登录用户名: xuxuzhaozhao//======================================================using System.Configuration;using System.Linq;using System.Net;using System.Net.Http;using System.Security.Claims;using System.Text;using System.Web;using System.Web.Helpers;using System.Web.Http;using System.Web.Http.Controllers;using YiCheng.Business.Model;using YiCheng.Common.DAL;using YiCheng.Common.Pagination;using YiCheng.Common.Tools;using YiCheng.Model.OutputModel;// ReSharper disable Allnamespace YiCheng.Web.Api{/// <summary>/// 权限管理筛选器/// </summary>public class YAuthorizeFilterAttribute : AuthorizeAttribute{private readonly string SUPERADMIN = ConfigurationManager.AppSettings["SUPERADMIN"];/// <summary>/// 身份验证/// </summary>/// <param name="actionContext"></param>public override void OnAuthorization(HttpActionContext actionContext){var username = "";var url = actionContext.RequestContext.Url.Request.RequestUri.AbsolutePath.ToUpper();username = HttpContext.Current.User.Identity.Name;#region 前后端彻底分离,使用OAuth来进行授权(2个小时过期时间)if (string.IsNullOrEmpty(username)){var x = actionContext.RequestContext.Principal.Identity;var identity = x as ClaimsIdentity;username = identity?.Claims.Where(t => t.Type == "yuser").Select(t => t.Value).SingleOrDefault();}#endregion//统一约定,当前页面var currentPage = HttpContext.Current.Request["currentPage"]?.ToUpper();//统一约定,订单编号var orderId = HttpContext.Current.Request["orderId"];if (!string.IsNullOrEmpty(username)){var user = new YUser(username);HttpContext.Current.User = user;if (IsAuth(url, user, currentPage, orderId)){base.IsAuthorized(actionContext);//为此请求授权}else{HandleUnauthorizedRequest(actionContext);}}//如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401else{var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);if (isAnonymous) base.OnAuthorization(actionContext);else HandleUnauthorizedRequest(actionContext);}}/// <summary>/// 校验该用户是否有权操作此控制器/// </summary>/// <param name="url"></param>/// <param name="user"></param>/// <param name="currentPage"></param>/// <param name="orderId"></param>/// <returns></returns>private bool IsAuth(string url, YUser user, string currentPage, string orderId){if (user.角色.Contains(SUPERADMIN)) return true;var flag = true;//查询该账号是否有权限请求这个urlusing (var db = new BaoJiaDb()){//该Url是否允许匿名访问var 匿名url = $"SELECT TOP 1 匿名访问 FROM 请求Url表 WHERE UPPER(请求Url) = @请求Url";var t = YDBHelper.ExecuteScalar2(匿名url, new { 请求Url = url })?.ToString();if (string.IsNullOrEmpty(t)) throw new YException($"当前页面:{currentPage?.ToLower()},url:{url?.ToLower()},没有加到请求Url字典表中,请检查!", 98);var 匿名访问 = bool.Parse(t);if (匿名访问) return true;var sql1 = $@"SELECT COUNT(1) FROM 请求权限管理表 uaLEFT JOIN dbo.请求Url表 u ON ua.请求UrlGUID = u.GUIDWHERE UPPER(u.请求Url) = @请求Url AND ua.种类 = '角色' AND UPPER(u.页面名) = @页面名AND ua.角色 IN ({YTools.Brackets(user.角色)}) AND ua.企业名称 = @企业名称";var 条件1 = int.Parse(YDBHelper.ExecuteScalar2(sql1, new{请求Url = url,页面名 = currentPage,企业名称 = user.企业名称}).ToString()) > 0;var sql2 = $@"SELECT COUNT(1) FROM 请求权限管理表 uaLEFT JOIN dbo.请求Url表 u ON ua.请求UrlGUID = u.GUIDWHERE UPPER(u.请求Url) = @请求Url AND ua.种类 = '账号' AND UPPER(u.页面名) = @页面名AND ua.角色 = @账号 AND ua.企业名称 = @企业名称";var 条件2 = int.Parse(YDBHelper.ExecuteScalar2(sql1, new{请求Url = url,账号 = user.账号,页面名 = currentPage,企业名称 = user.企业名称}).ToString()) > 0;//只要该账号所属的其中一个角色允许访问该url,则该账号就可访问if (flag == true && (条件1 || 条件2))return true;}throw new YException($"当前页面:{currentPage?.ToLower()}的url{url?.ToLower()},未授权不可访问", 98);}/// <summary>/// 处理未授权请求/// </summary>/// <param name="filterContext"></param>protected override void HandleUnauthorizedRequest(HttpActionContext filterContext){base.HandleUnauthorizedRequest(filterContext);var response = filterContext.Response = filterContext.Response ?? new HttpResponseMessage();response.StatusCode = HttpStatusCode.Forbidden;//Result类 可自行创建,具体为返回的content信息var content = new YResult();content.Failure(99, "未授权用户或已过期请重新登录.");content.Data = "/";response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");}}}