天天看点

记录一次 .net core 2.0 JWT过程

本文章参考了其他朋友的博客,但是我确实不知道参考的谁了,所以自己记录一下,防止忘记。

首先创建了一个ApiAuthorizedByJWT类库·,具体内容如下(四部分分别是 生成的jwt类,角色权限对应关系,jwt验证方法,许可要求类):

1 using Microsoft.AspNetCore.Mvc;
 2 using System;
 3 using System.IdentityModel.Tokens.Jwt;
 4 using System.Security.Claims;
 5 
 6 namespace ApiAuthorizedByJWT
 7 {
 8     public class JWTAuthorizeCLASS
 9     {
10         public bool Status;
11         public string access_token;
12         public double expires_in;
13         public string token_type;
14         public static dynamic BuildOwnToken(Claim[] claims, PermissionRequirement permissionRequirement)
15         {
16             var now = DateTime.UtcNow;
17             var jwt = new JwtSecurityToken(
18                 issuer: permissionRequirement.Issuer,
19                 audience: permissionRequirement.Audience,
20                 claims: claims,
21                 notBefore: now,
22                 expires: now.Add(permissionRequirement.Expiration),
23                 signingCredentials: permissionRequirement.SigningCredentials
24             );
25             var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
26             JWTAuthorizeCLASS rtres = new JWTAuthorizeCLASS
27             {
28                 Status = true,
29                 access_token = encodedJwt,
30                 expires_in = permissionRequirement.Expiration.TotalMilliseconds,
31                 token_type = "Bearer"
32             };
33 
34             
35             return rtres;
36         }
37     }
38 }

      
using System;
using System.Collections.Generic;
using System.Text;

namespace ApiAuthorizedByJWT
{
    /// <summary>
    /// 角色与权限url对应的类
    /// </summary>
    public class Permission
    {
        /// <summary>
        /// 角色名称
        /// </summary>
        public virtual string RoleName { get; set; }

        /// <summary>
        /// 链接地址
        /// </summary>
        public virtual string Url { get; set; }


    }

    
}
      
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// 这里必须注意:此处引用了nuget包:Microsoft.AspNetCore.Mvc.Abstractions;否则这个Microsoft.AspNetCore.Mvc不存在 以及Microsoft.AspNetCore.All
/// </summary>
namespace ApiAuthorizedByJWT
{
    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        /// <summary>
        /// 验证方案提供对象
        /// </summary>
        public IAuthenticationSchemeProvider Schemes { get; set; }
        /// <summary>
        /// 自定义策略参数
        /// </summary>
        public PermissionRequirement Requirement
        { get; set; }
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="schemes"></param>
        public PermissionHandler(IAuthenticationSchemeProvider schemes)
        {
            Schemes = schemes;
        }
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            ////赋值用户权限       
            Requirement = requirement;
            //从AuthorizationHandlerContext转成HttpContext,以便取出表求信息
            var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;
            //请求Url
            var questUrl = httpContext.Request.Path.Value.ToLower();
            //判断请求是否停止
            var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
            foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
            {
                var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name) as IAuthenticationRequestHandler;
                if (handler != null && await handler.HandleRequestAsync())
                {
                    context.Fail();
                    return;
                }
            }
            //判断请求是否拥有凭据,即有没有登录
            var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
            if (defaultAuthenticate != null)
            {
                var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
                //result?.Principal不为空即登录成功
                if (result?.Principal != null)
                {
                    httpContext.User = result.Principal;
                    //权限中是否存在请求的url
                    if (Requirement.Permissions.GroupBy(g => g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0)
                    {
                        var name = httpContext.User.Claims.SingleOrDefault(s => s.Type == requirement.ClaimType).Value;
                        //验证权限
                        if (Requirement.Permissions.Where(w => w.RoleName == name && w.Url.ToLower() == questUrl).Count() <= 0)
                        {
                            
                            context.Fail();
                            return;
                            
                        }

                        context.Succeed(requirement);
                    }

                    return;
                    //var userroles = requirement.Permissions;
                }
            }
           
            if (!questUrl.Equals(Requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST")
               || !httpContext.Request.HasFormContentType))
            {  
                
                context.Fail();
                return;
            }

            context.Succeed(requirement);

        }
    }
}      
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Text;

namespace ApiAuthorizedByJWT
{
    /// <summary>
    /// 许可要求
    /// </summary>
    public class PermissionRequirement:IAuthorizationRequirement
    {
        /// <summary>
        /// 用户权限集合
        /// </summary>
        public List<Permission> Permissions { get; private set; }

        /// <summary>
        /// 无权限action
        /// </summary>
        public string DeniedAction { get; set; } = "/Api/ReLogin";

        /// <summary>
        /// 认证授权类型
        /// </summary>
        public string ClaimType { internal get; set; }
        /// <summary>
        /// 请求路径
        /// </summary>
        public string LoginPath { get; set; } = "/Api/Login";
        /// <summary>
        /// 发行人
        /// </summary>
        public string Issuer { get; set; }
        /// <summary>
        /// 订阅人
        /// </summary>
        public string Audience { get; set; }
        /// <summary>
        /// 过期时间
        /// </summary>
        public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(60);
        /// <summary>
        /// 签名验证
        /// </summary>
        public SigningCredentials SigningCredentials { get; set; }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="deniedAction">拒约请求的url</param>
        /// <param name="permissions">权限集合</param>
        /// <param name="claimType">声明类型</param>
        /// <param name="issuer">发行人</param>
        /// <param name="audience">订阅人</param>
        /// <param name="signingCredentials">签名验证实体</param>
        public PermissionRequirement(string deniedAction, List<Permission> permissions, string claimType, string issuer, string audience, SigningCredentials signingCredentials)
        {
            ClaimType = claimType;
            DeniedAction = deniedAction;
            Permissions = permissions;
            Issuer = issuer;
            Audience = audience;
            SigningCredentials = signingCredentials;
        }
    }
}      

那么在真正的使用中,要在core中添加上对应的一些数据信息。首先常见一个关于登录用户的类

using ApiAuthorizedByJWT;
using Dapper;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using new_m1_1_0.Models.interfaces;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace new_m1_1_0.Models.models
{
    public class LoginUser:ILoginUser
    {
        public string Username;
        public string UserID;
        public string Accid;
        public string Password;
        public string Acctoken;
        public List<SourceWithRole> LRC;
        public JWTAuthorizeCLASS apitoken;

        private bool isInit = false;
        public LoginUser(string ID,string Key,Func<string,string,string,bool> CheckMethed, string connectstring)
        {
            //--------------------校验方法--------------------------------
            //pass
            if (CheckMethed(ID, Key, connectstring))
            {
               
                Password = Key;
                IDbConnection conn = new MySql.Data.MySqlClient.MySqlConnection(connectstring);
                string sql1 = "select a.user_name,a.role_key,b.name,b.remark,c.url,c.name as func_name,c.sourse,d.resource_key,e.source_name from m1_user_roles a,m1_role b,m1_resource c,m1_permission d,m1_sourse e where a.user_name = @ID and b.role_key = a.role_key and d.role_key = a.role_key and c.resource_key = d.resource_key and e.source_key = c.sourse and e.role_key = a.role_key";
                List<LoginUserInfo> loginUserInfo = conn.Query<LoginUserInfo>(sql1, new { id = ID }).ToList();
                string sql2 = "select a.user_name,a.accid,a.acctoken,b.nick_name from m1_user_im a,m1_user b where a.user_name = @id and b.user_name = a.user_name";
                List < LoginUserNeteaseInfo> loginUserNeteaseInfo = conn.Query<LoginUserNeteaseInfo>(sql2, new { id = ID }).ToList();
                LRC = new List<SourceWithRole>();
                List<string> sourseL = new List<string>();
                
                for (int i = 0; i < loginUserInfo.Count; i++)
                {
                    if (!sourseL.Contains(loginUserInfo[i].sourse))
                    {
                        sourseL.Add(loginUserInfo[i].sourse);
                        SourceWithRole sourceWithRole = new SourceWithRole();
                        sourceWithRole.L = new List<RoleWithCode>();
                        var rwc = new RoleWithCode();
                        rwc.Code = loginUserInfo[i].resource_key;
                        rwc.RoleName = loginUserInfo[i].name;
                        rwc.RoleKey = loginUserInfo[i].role_key;
                        rwc.Url = loginUserInfo[i].url;

                        sourceWithRole.L.Add(rwc);

                        sourceWithRole.SourceCode = loginUserInfo[i].sourse;
                        sourceWithRole.SourceName = loginUserInfo[i].source_name;

                        LRC.Add(sourceWithRole);
                    }
                    else
                    {
                        for (int j = 0; j < LRC.Count; j++)
                        {
                            if (LRC[j].SourceCode == loginUserInfo[i].sourse)
                            {
                                var rwc = new RoleWithCode();
                                rwc.Code = loginUserInfo[i].resource_key;
                                rwc.RoleName = loginUserInfo[i].name;
                                rwc.RoleKey = loginUserInfo[i].role_key;
                                rwc.Url = loginUserInfo[i].url;

                                LRC[j].L.Add(rwc);
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }
                }

                try
                {
                    Username = loginUserNeteaseInfo[0].nick_name;
                    Accid = loginUserNeteaseInfo[0].accid;
                    Acctoken = loginUserNeteaseInfo[0].acctoken;
                    UserID = loginUserNeteaseInfo[0].user_name;

                    this.apitoken = GetLoginUserToken();
                }
                catch (Exception ex)
                {
                    Username = "";
                    Accid = "";
                    Acctoken = "";
                    UserID = "";
                    LRC = null;
                }
            }
            else
            {
                Username = "";
                UserID = "";
                Password = "";
                Accid = "";
                Acctoken = "";
                LRC = null;
            }
        }

        public JWTAuthorizeCLASS GetLoginUserToken()
        {
            if (LRC == null || LRC.Count < 1)
            {
                return null;
            }

            var symmetricKeyAsBase64 = "TTT11111TTT111TTTTT11TTTTTT11111111111";//audienceConfig["Secret"];
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            int apicount = 0;

            List<string> roles = new List<string>();
            var permission = new List<Permission>();

            for (int i = 0; i < LRC.Count; i++)
            {
                for (int j = 0; j < LRC[i].L.Count; j++)
                {
                    if (roles.Contains(LRC[i].L[j].RoleKey))
                    {

                    }
                    else
                    {
                        roles.Add(LRC[i].L[j].RoleKey);
                    }

                    permission.Add(new Permission { Url = LRC[i].L[j].Url,RoleName= LRC[i].L[j].RoleKey});
                }
            }

            List<System.Security.Claims.Claim> claimArray = new List<Claim>();
            for (int i = 0; i < roles.Count; i++)
            {
                claimArray.Add(new Claim(ClaimTypes.Role, roles[i]));
            }
            claimArray.Add(new Claim(ClaimTypes.Name, UserID));
            return JWTAuthorizeCLASS.BuildOwnToken(claimArray.ToArray(), new PermissionRequirement("/api/login", permission, ClaimTypes.Role, "lsnct", "everyone", signingCredentials));
            
        }
    }

    public class RoleWithCode
    {
        /// <summary>
        /// 角色名称
        /// </summary>
        public string RoleName;
        /// <summary>
        /// 权限code
        /// </summary>
        public string Code;
        /// <summary>
        /// 链接
        /// </summary>
        public string Url;
        /// <summary>
        /// 角色关键字
        /// </summary>
        public string RoleKey;
    }

    public class SourceWithRole
    {
        /// <summary>
        /// 资源模块代码
        /// </summary>
        public string SourceCode;
        /// <summary>
        /// 资源模块名称
        /// </summary>
        public string SourceName;
        /// <summary>
        /// 所属角色与api列表
        /// </summary>
        public  List<RoleWithCode> L;
    }
}      

然后在控制器中处理

[HttpPost]
        public JsonResult Post()
        {
            
            var username = HttpContext.Request.Form["username"].ToString().Trim();//获取
            var pwd = HttpContext.Request.Form["pwd"].ToString().Trim();

            LoginUser LU = new LoginUser(username,pwd,CheckLogin.checkmethed1, appSettings.dbcc_sys);
            LU.Password = "";
            return new JsonResult(LU);

           
        }      

生成了token后,后面会拿这个token访问接口。

在对应的工程的startup.cs中处理

var symmetricKeyAsBase64 = "TTT11111TTT111TTTTT11TTTTTT11111111111";//audienceConfig["Secret"];
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = "lsnct", //audienceConfig["Issuer"],
                ValidateAudience = true,
                ValidAudience = "everyone",
                //audienceConfig["Audience"],
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            services.AddAuthorization(options =>
            {
                //var permission = GetAllPermission();
                List<Permission> permission = null;
                if (permission == null)
                {
                    //这个集合模拟用户权限表,可从数据库中查询出来
                    permission = new List<Permission> {
                              new Permission {  Url="/api/getValues1", RoleName="system"},
                              new Permission {  Url="/api/values/getValues1", RoleName="admin"},
                              new Permission{ Url="/api/getValues3", RoleName="admin"},
                              new Permission{  Url="/api/Products/GetMomentDetails", RoleName="system"}
                          };
                }
                //如果第三个参数,是ClaimTypes.Role,上面集合的每个元素的Name为角色名称,如果ClaimTypes.Name,即上面集合的每个元素的Name为用户名
                //var permissionRequirement = new PermissionRequirement("/api/denied", permission, ClaimTypes.Role, audienceConfig["Issuer"], audienceConfig["Audience"], signingCredentials);
                var permissionRequirement = new PermissionRequirement("/Api/Login", permission, ClaimTypes.Role, "lsnct", "everyone", signingCredentials);
                options.AddPolicy("Permission",
                          policy => policy.Requirements.Add(permissionRequirement));
            }).AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o =>
            {
                //不使用https
                o.RequireHttpsMetadata = false;
                o.TokenValidationParameters = tokenValidationParameters;
            });
            //注入授权Handler
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
            services.AddMvc()
                .AddJsonOptions(options=>
                {
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;//忽略循环引用
                    options.SerializerSettings.ContractResolver = new DefaultContractResolver();//不使用驼峰样式key
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";//时间格式化
                });      

最后在对应接口加上[Authorize("Permission")]标记即可。

转载于:https://www.cnblogs.com/lsnct/p/8474229.html