jwt生成和url解析

1、公共方法

using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Principal;

namespace HRS.Web.Helper
{
    public class TokenHelper
    {
        private static string _Secret = ConfigurationManager.AppSettings["TokenSercert"];
        private static string _Issuer = ConfigurationManager.AppSettings["Issuer"];

        public static string GenerateToken(string username, int expireMinutes = 120)
        {
            var symmetricKey = Convert.FromBase64String(_Secret);  // 生成二进制字节数组
            var tokenHandler = new JwtSecurityTokenHandler(); // 创建一个JwtSecurityTokenHandler类用来生成Token
            var now = DateTime.UtcNow; // 获取当前时间
            var tokenDescriptor = new SecurityTokenDescriptor // 创建一个 Token 的原始对象
            {
                Subject = new ClaimsIdentity(new[] // Token的身份证,类似一个人可以有身份证,户口本
                        {
                            new Claim("username", username) // 可以创建多个
                        }),
                Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)), // Token 有效期
                NotBefore = now,
                IssuedAt = now,
                Issuer = _Issuer,
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256)
            };
            var stoken = tokenHandler.CreateToken(tokenDescriptor); // 生成一个编码后的token对象实例
            var token = tokenHandler.WriteToken(stoken); // 生成token字符串,给前端使用
            return token;
        }

        /// <summary>
        /// 验证token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static IPrincipal AuthenticateJwtToken(string token)
        {
            string userName;
            if (ValidateToken(token, out userName))
            {
                // 这里就是验证成功后要做的逻辑,也就是处理WWW-Authenticate验证
                var info = new List<Claim>()
                {
                    new Claim(ClaimTypes.Name, userName)
                };// 根据验证token后获取的用户名重新建一个声明,你可以在这里创建多个声明
                // Claims就像你身份证上面的信息,一个Claim就是一条信息,将这些信息放在ClaimsIdentity就构成身份证
                var infos = new ClaimsIdentity(info, "Jwt");
                // 将上面的身份证放在ClaimsPrincipal里面,相当于把身份证给持有人
                IPrincipal user = new ClaimsPrincipal(infos);
                return user;
            }
            return null;
        }

        private static bool ValidateToken(string token, out string userName)
        {
            userName = null;
            var simplePrincipal = GetPrincipal(token); // 调用自定义的GetPrincipal获取Token的信息对象
            var identity = simplePrincipal.Identity as ClaimsIdentity; // 获取主声明标识
            if (identity == null) return false;
            if (!identity.IsAuthenticated) return false;
            var userNameClaim = identity.FindFirst("username"); // 获取声明类型是ClaimTypes.Name的第一个声明
            userName = userNameClaim.Value; // 获取声明的名字,也就是用户名
            if (string.IsNullOrEmpty(userName)) return false;
            return true;
        }

        /// <summary>
        /// 此方法用解码字符串token,并返回秘钥的信息对象
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private static ClaimsPrincipal GetPrincipal(string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler(); // 创建一个JwtSecurityTokenHandler类,用来后续操作
                var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken; // 将字符串token解码成token对象
                if (jwtToken == null) throw new ShowInfoException("token错误");

                var symmetricKey = Convert.FromBase64String(_Secret); // 生成编码对应的字节数组
                var validationParameters = new TokenValidationParameters() // 生成验证token的参数
                {
                    RequireExpirationTime = true, // token是否包含有效期
                    ValidateIssuer = false, // 验证秘钥发行人,如果要验证在这里指定发行人字符串即可
                    ValidIssuer = _Issuer,
                    ValidateAudience = false, // 验证秘钥的接受人,如果要验证在这里提供接收人字符串即可
                    IssuerSigningKey = new SymmetricSecurityKey(symmetricKey), // 生成token时的安全秘钥
                    ValidateLifetime = false, //是否验证失效时间
                    LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken scToken, TokenValidationParameters vParameters) => expires > DateTime.UtcNow,
                };
                SecurityToken securityToken; // 接受解码后的token对象
                var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
                return principal; // 返回秘钥的主体对象,包含秘钥的所有相关信息
            }
            catch (SecurityTokenInvalidLifetimeException ex)
            {
                throw new ShowInfoException("token超时,请重新获取token");
            }
            catch (SecurityTokenInvalidIssuerException ex)
            {
                throw new ShowInfoException("token发行人错误,应该是【{0}】", _Issuer);
            }
            catch (Exception ex)
            {
                throw new ShowInfoException("token错误");
            }
        }
    }
}
View Code

2、生成

respone.access_token = TokenHelper.GenerateToken(model.businesslicenseNo, 5);

3、解析和重定向

using HRS.Lib.Comm.Exceptions;
using HRS.Service.Contract.ContractParam.Base;
using HRS.Service.Contract.Security;
using HRS.Web.Helper;
using HRS.Web.JsonCommunication;
using HRS.Web.Rule;
using HRS.Web.WcfClient;
using System;
using System.Net;
using System.Text;
using System.Web.Mvc;

namespace HRS.Web.Controllers
{
    public class LoginController : BaseController
    {
        public const string USER_NAME_VERIFYCODE_KEY_NAME = "==VERIFYCODE==";
        //
        // GET: /Login/
        [AllowAnonymous]
        public ActionResult Index()
        {
            try
            {
                var authorization = Request.QueryString["jwt"]; // 获取请求的token对象
                if (authorization == null) throw new ShowInfoException("缺省jwt参数");

                var principal = TokenHelper.AuthenticateJwtToken(authorization); // 调用此方法,根据token生成对应的"身份证持有人"
                if (principal == null)
                {
                    throw new ShowInfoException("jwt参数格式不正确");
                }

                Login(principal.Identity.Name);
                return Redirect("~/dashboard.html");
            }
            catch(Exception e)
            {
                BusinessEngine.Logger.Error(e);
                return Content(e.Message);
            }
        }

        /// <summary>
        /// 登录
        /// </summary>
        private void Login(string username)
        {
            BaseRequstJson requestJson = new BaseRequstJson()
            {
                MethodFullName = "PotentialCustomer.Login",
                ParamTypeName = "LoginReqParam",
                ParamJsonData = "{\"Username\":\"" + username + "\",\"IsTempPwdLogin\":true,\"ExtraData\":{\"VerifyCode\":\"\"}}"
            };
            var param = GetParam(requestJson.ParamTypeName, requestJson.ParamJsonData);
            var paramUser = param as LoginReqParam;
            if (paramUser == null)
            {
                throw new ArgumentNullException("param type is not ParamUser");
            }
            // 登录信息
            ValidateIP(paramUser);

            //与wcf服务通讯
            var resp = ServiceCommunicator.Login<BaseResponse>(requestJson.MethodFullName, paramUser, paramUser.UserName);

            paramUser.UserID = resp.ExtraData.GetStr("UserID");

            SessionAdapter[BaseControllerEngine.CUR_USER_SESSION_NAME] = paramUser;
            SessionAdapter[BaseControllerEngine.CUR_USER_RES_NAME] = new UserRes();
            Session["UserID"] = paramUser.UserID;
            Session["UserType"] = paramUser.UserType;
            Session["LoginTime"] = DateTime.Now.ToString("yyyyMMddHHmmssffff");

            Session["UserCName"] = resp.ExtraData.GetStr("UserCName");
            Session["InstitutionName"] = resp.ExtraData.GetStr("InstitutionName");
        }

        /// <summary>
        /// 验证IP
        /// </summary>
        /// <param name="paramUser"></param>
        private void ValidateIP(LoginReqParam paramUser)
        {
            var sb = new StringBuilder();
            sb.Append("【UserAgent:】" + Request.UserAgent);
            sb.Append("【UserHostAddress:】" + Request.UserHostAddress);
            sb.Append("【UserHostName:】" + Request.UserHostName);

            string userHostAddress = string.Empty;
            if (null != Request.ServerVariables["HTTP_X_FORWARDED_FOR"])
            {
                userHostAddress = Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim();
            }
            //否则直接读取REMOTE_ADDR获取客户端IP地址
            if (string.IsNullOrEmpty(userHostAddress))
            {
                userHostAddress = Request.ServerVariables["REMOTE_ADDR"];
            }
            //前两者均失败,则利用Request.UserHostAddress属性获取IP地址,但此时无法确定该IP是客户端IP还是代理IP
            if (string.IsNullOrEmpty(userHostAddress))
            {
                userHostAddress = Request.UserHostAddress;
            }
            //最后判断获取是否成功,并检查IP地址的格式(检查其格式非常重要)
            if (string.IsNullOrEmpty(userHostAddress) || !HRS.Lib.Comm.IO.WebUtil.IsIP(userHostAddress))
            {
                userHostAddress = "172.0.0.1";
            }
            sb.Append("【ClientIP:】" + userHostAddress);

            for (var i = 0; i < Request.ServerVariables.AllKeys.Length; i++)
            {
                var key = Request.ServerVariables.AllKeys[i];
                sb.Append(string.Format("【ServerVariables-{0}:】{1}", key, Request.ServerVariables[key]));
            }
            paramUser.ClientIP = userHostAddress;
            paramUser.LoginInfo = sb.ToString();
            #region 当前服务器信息
            var serverhost = Dns.GetHostEntry(Dns.GetHostName());
            var serverIP = string.Empty;
            foreach (IPAddress ip in serverhost.AddressList)
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    serverIP = ip.ToString();
                    break;
                }
            }
            paramUser.ServerInfo = string.Format("{0}:{1}", serverhost.HostName, serverIP);
            #endregion
        }
    }
}
View Code

4、调用

http://localhost:8888/Login?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh4eHh4LXh4eDEiLCJuYmYiOjE2NDc4MzE2NDksImV4cCI6MTY0NzgzMTk0OSwiaWF0IjoxNjQ3ODMxNjQ5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAifQ.8OnP1WF5EVI3O_TOnsVCkS_PC0tvtJQj268haOpuOY4

 

posted @ 2022-03-22 10:50  江境纣州  阅读(117)  评论(0编辑  收藏  举报