WebAPI/Service/JwtAuthorizeAttribute.cs
@@ -1,43 +1,128 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using WebAPI.Models;
using WebAPI.Utility;
public class JwtAuthorizeAttribute : AuthorizationFilterAttribute
{
    private json objjson = new json();
    private SQLHelper.ClsCN oCN = new SQLHelper.ClsCN();
    private Pub_Class.ClsXt_SystemParameter oSystemParameter = new Pub_Class.ClsXt_SystemParameter();
    private string campanyName = "";
    public JwtAuthorizeAttribute()
    {
        if (oSystemParameter.ShowBill(ref DBUtility.ClsPub.sErrInfo))
        {
            campanyName = oSystemParameter.omodel.WMS_CampanyName;
        }
    }
    // 同步鉴权
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        // 检查匿名访问
        if (IsAnonymousAllowed(actionContext)) return;
        // 获取Token
        var token = GetTokenFromHeader(actionContext);
        if (string.IsNullOrEmpty(token))
        try
        {
            HandleUnauthorized(actionContext);
            return;
        }
            // 检查匿名访问
            if (IsAnonymousAllowed(actionContext)) return;
        // 验证Token
        var principal = JWTHelper.ValidateToken(token, "123");
        if (principal == null)
            // 获取Token
            var token = GetTokenFromHeader(actionContext);
            if (string.IsNullOrEmpty(token))
            {
                HandleUnauthorized(actionContext);
                return;
            }
            // 验证Token
            // 可以增加更细粒度的控制,添加 根据组织ID 判断(问题: 公司名不能使用中文,可能需要添加英文字段)
            var principal = JWTHelper.ValidateToken(token);
            if (principal == null)
            {
                HandleUnauthorized(actionContext);
                return;
            }
            // 设置用户
            actionContext.RequestContext.Principal = principal;
            // 验证是否拥有访问模块的权限
            // 有两种判断方式 一种是通过角色去判断,一种是通过用户去判断 目前暂时不做区分,后续可增加系统参数来进行区分
            // 获取控制器描述器
            HttpControllerDescriptor controllerDescriptor = actionContext.ControllerContext.ControllerDescriptor;
            // //获取控制器类型
            Type controllerType = controllerDescriptor.ControllerType;
            // // 获取控制器级别标签
            var controllerAttr = controllerType.GetCustomAttribute<PermissionAttribute>();
            // 获取动作级别标签
            var actionAttr = actionContext.ActionDescriptor
            .GetCustomAttributes<PermissionAttribute>()
            .FirstOrDefault();
            string PermissionStr = string.Empty;
            // 判断控制器级别上是否启用了鉴权标签
            if(controllerAttr != null && !string.IsNullOrWhiteSpace(controllerAttr.HModName))
            {
                PermissionStr += controllerAttr.HModName;
                // 查看是否需要更细粒度的控制
                if(actionAttr != null && !string.IsNullOrWhiteSpace(actionAttr.Operate))
                {
                    // 该动作对应的模块名和控制器名是否不一致
                    if (string.IsNullOrWhiteSpace(actionAttr.HModName))
                    {
                        PermissionStr = actionAttr.HModName + actionAttr.Operate;
                    }
                    else
                    {
                        PermissionStr += actionAttr.Operate;
                    }
                }
                if(!string.IsNullOrWhiteSpace(PermissionStr))
                {
                    if (!DBUtility.ClsPub.Security_Log(PermissionStr, 1, false, JWTHelper.getUserName(token)))
                    {
                        HandleForbidden(actionContext);
                        return;
                    }
                }
            }else if (string.IsNullOrWhiteSpace(actionAttr.HModName) && string.IsNullOrWhiteSpace(actionAttr.Operate))
            {
                // 单独在动作上启用鉴权功能
                PermissionStr = actionAttr.HModName + actionAttr.Operate;
                if (!string.IsNullOrWhiteSpace(PermissionStr))
                {
                    if (!DBUtility.ClsPub.Security_Log(PermissionStr, 1, false, JWTHelper.getUserName(token)))
                    {
                        HandleForbidden(actionContext);
                        return;
                    }
                }
            }
        }
        catch (Exception e)
        {
            HandleUnauthorized(actionContext);
            return;
            HandleError(actionContext, e.Message);
        }
        // 设置用户
        actionContext.RequestContext.Principal = principal;
    }
    // 异步鉴权(满足WebAPI 2要求,兼容.NET4.5)
    // 异步鉴权
    public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        OnAuthorization(actionContext);
@@ -45,7 +130,7 @@
        return Task.FromResult(0);
    }
    // 是否允许匿名访问
    // 是否允许匿名访问(控制器级别和动作级别都可用)
    private bool IsAnonymousAllowed(HttpActionContext context)
    {
        return
@@ -70,7 +155,34 @@
    private void HandleUnauthorized(HttpActionContext context)
    {
        var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        response.Content = new StringContent("未授权,请登录后重试");
        objjson.code = "0";
        objjson.count = 0;
        objjson.Message = "未授权,请登录后重试";
        response.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(objjson),
            System.Text.Encoding.UTF8, "application/json");
        context.Response = response;
    }
    // 403 无权限
    private void HandleForbidden(HttpActionContext context)
    {
        var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
        objjson.code = "0";
        objjson.count = 0;
        objjson.Message = "您没有该模块权限,请与管理员联系!";
        response.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(objjson),
            System.Text.Encoding.UTF8, "application/json");
        context.Response = response;
    }
    private void HandleError(HttpActionContext context, string ErrorInfo)
    {
        var response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
        objjson.code = "0";
        objjson.count = 0;
        objjson.Message = "服务器异常: " + ErrorInfo;
        response.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(objjson),
            System.Text.Encoding.UTF8, "application/json");
        context.Response = response;
    }
}