美文网首页
EF+SqlServer/Mysql(三)JWT+Authori

EF+SqlServer/Mysql(三)JWT+Authori

作者: 醉酒的姑娘 | 来源:发表于2020-12-21 15:34 被阅读0次

    集成JWT权限认证

    为什么要使用JWT,我们先来看看传统的身份校验方式
    用户向服务器发送用户名和密码->服务器验证通过后,在当前session对话里保存用户登录信息,比如用户角色,用户名,登录时间等->服务器向用户返回一个session_id,写入用户的cookie->随后的用户每次发送请求都会将session_id传回服务器->服务器搜到session_id,找到前期保存的数据,由此得知用户的身份
    这种模式的问题在于,扩展性不好,单机情况下没有问题,如果是服务器集群,要求session数据共享,每台服务器都能够读取session,如果session存储的节点挂了,那么整个服务都会瘫痪,体验相当不好,风险也很高,相比之下,JWT的实现方式是将用户信息存储在客户端,服务端不进行保存,每次请求都把令牌带上来校验用户的登录状态,这样服务器就变成了无状态的,服务器集群也很好扩展。

    当用户需要访问带权限验证的API时,应该使用承载模式发送JWT,通常在Authorization标头,格式如下:
    Authorization:Bearer <boken>

    网站的功能简介
    登录成功后将用户信息写入Claim对象生成token返回web端,写入cookie,当用户修改密码时,通过ajax调用Api接口在头部添加Authorization:Bearer <token>发送请求,authorize会验证token是否有效,如果失效则返回401,成功则进行密码修改的操作。

    登录API

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("Login")]
        public async Task<IActionResult> Login(UserDto user)
        {
            var result = new ResultInclusion();
            if (string.IsNullOrEmpty(user.UserName))
            {
                result.Code = -1;
                result.Msg = "请输入账号";
                return new JsonResult(result);
            }
            if (string.IsNullOrEmpty(user.Password))
            {
                result.Code = -1;
                result.Msg = "请输入密码";
                return new JsonResult(result);
            }
            //dto.LoginIP = ip.ToString();
            ////获取客户端浏览器信息
            //dto.Explorer = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
            ////获取客户端浏览器信息
            //dto.ClientOS = HttpContextHelper.GetOsVersion(dto.Explorer);
    
            var usermodel = await _service.GetAsync(p=>p.UserName==user.UserName);
            if (usermodel != null)
            {
                if (usermodel.Password == GetMD5.Get_MD5(user.Password, "utf-8"))
                {
                    var claims = new List<Claim>()
                    {
                        new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                        new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
                        new Claim(ClaimTypes.Name,user.UserName)
                    };
                     
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"]));
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                    var token = new JwtSecurityToken(
                        issuer:Configuration["Jwt:Domain"],
                        audience:Configuration["Jwt:Domain"],
                        claims:claims,
                        expires:DateTime.Now.AddMinutes(30),
                        signingCredentials:creds
                        );
                  var accesstoken=  new JwtSecurityTokenHandler().WriteToken(token);
                    result.Code = 0;
                    result.Msg = "登录成功";
                    result.Data = new
                    {
                        username = user.UserName,
                        token =accesstoken
                    };
                    return new JsonResult(result);
                }
                else {
                    result.Code = -1;
                    result.Msg = "密码错误";
                    return new JsonResult(result);
                }
            }
            else {
                result.Code = -1;
                result.Msg = "用户名不存在";
                return new JsonResult(result);
            }
        }
    

    appsettings.json配置

      "Jwt": {
    "SecretKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB",
    "Domain": "http://localhost:5001"
    

    }

    startup.cs ConfigureServices方法中添加JWT相关配置

                //添加权限认证+jwt认证
            services.AddAuthentication(b =>
            {
                b.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                b.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
                .AddJwtBearer(options => {
                    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                    {
                        ValidateIssuer = true,//是否验证Issuer
                        ValidateAudience = true,//是否验证Audience
                        ValidateLifetime = true,//是否验证失效时间
                        ClockSkew = TimeSpan.FromMilliseconds(30),
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidAudience = Configuration["Jwt:Domain"],//Audience
                        ValidIssuer = Configuration["Jwt:Domain"],//Issuer,这两项和前面签发jwt的设置一致
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"]))//拿到SecurityKey
    
                    };
                });
    

    Configure方法中添加权限过滤器

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();
    
            app.UseMvc();
        }
    

    Web端:用户登录成功后返回的token写进cookie

        <form class="form-signin form-group" id="AppForm">
        <h2 class="form-signin-heading">欢迎使用我的Blog</h2>
        <label for="inputEmail" >账号</label>
        <input type="text" id="username" name="username" class="form-control" placeholder="请输入账号" value="liulei" required autofocus>
        <label for="inputPassword" >密码</label>
        <input type="password" id="password" name="password" class="form-control" placeholder="请输入密码" value="123456" required>
        <button class="btn btn-lg btn-primary btn-block" id="loginForm" type="submit">登录</button>
        </form>      
    
    
                    $.ajax({
                    type: 'post',
                    url: url + "/api/user/Login",
                    data:JSON.stringify( { UserName: $("#username").val(), Password: $("#password").val() }),
                    contentType:'application/json',
                    success: function (data) {
                       //写入cookie
                        $.cookie("access_token", data.data.token, {
                            expires: new Date().getTime() + (30 * 60 * 1000)
                            , path: '/'
                        });
                       console.log(data);
                    },
                    error: function (xhr) {
                        $('button[type="submit"]').text('登录').removeAttr('disabled');
                    },
                    beforeSend: function (XHR) {
                        $('button[type="submit"]').text('登录中...').attr('disabled', 'disabled');
                    },
                    complete: function (XHR, TS) {
                        $('button[type="submit"]').text('登录').removeAttr('disabled');
                    }
                });
    

    修改密码

    <form class="form-signin form-group" id="AppForm">
        <h2 class="form-signin-heading">修改密码</h2>
        <label for="inputEmail" >旧密码</label>
        <input type="password" id="oldpassword" name="oldpassword" class="form-control" placeholder="请输入旧密码" required>
        <label for="inputPassword" >新密码</label>
        <input type="password" id="newpassword" name="newpassword" class="form-control" placeholder="请输入新密码" required>
    
        <button class="btn btn-lg btn-primary btn-block" id="loginForm" type="submit">登录</button>
    </form>      
    
    
          $.ajax({
                    type: 'post',
                    url: url + "/api/user/UpdatePWD",
                    data: JSON.stringify({ OldPassWord: $("#oldpassword").val(), Password: $("#newpassword").val() }),
                    contentType: 'application/json',
                    beforeSend: function (XHR) {
                        XHR.setRequestHeader("Authorization", "bearer " + $.cookie("access_token"));
                    },
                   success: function (data) {
                       console.log(data);
                    },
                    error: function (xhr) {
                        $('button[type="submit"]').text('确定').removeAttr('disabled');
                    },
                    complete: function (XHR, TS) {
                        $('button[type="submit"]').text('确定').removeAttr('disabled');
                    }
                });
    

    修改密码API

        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("UpdatePWD")]
        [Authorize]
        public async Task<IActionResult> UpdatePWD(UserDto user) {
            var result = new ResultInclusion();
            //从claim中获取用户信息
            var schemeProvider = HttpContext.RequestServices.GetService(typeof(IAuthenticationSchemeProvider)) as IAuthenticationSchemeProvider;
            var defaultAuthenticate = await schemeProvider.GetDefaultAuthenticateSchemeAsync();
            if (defaultAuthenticate != null)
            {
                var JWTClaim = await HttpContext.AuthenticateAsync(defaultAuthenticate.Name);
                var ClaimUser = JWTClaim?.Principal;
                if (ClaimUser != null)
                {
                    var userPassword = GetMD5.Get_MD5(user.OldPassWord, "utf-8");
                    var userinfo = await _service.GetAsync(p => p.UserName == ClaimUser.Identity.Name);
                    if (userinfo!=null&&userinfo.Password == userPassword)
                    {
                        userinfo.Password = GetMD5.Get_MD5(user.Password, "utf-8");
                        result.Data = await _service.UpdateAsync(userinfo);
                        result.Code = 0;
                        result.Msg = "修改成功";
                    }
                    else
                    {
                        result.Code = -1;
                        result.Msg = "旧密码不正确";
                    }
                }
            }
            
            return new JsonResult(result);
        }
    

    若未登录直接修改密码则返回401权限未通过:


    image.png

    相关文章

      网友评论

          本文标题:EF+SqlServer/Mysql(三)JWT+Authori

          本文链接:https://www.haomeiwen.com/subject/utmrnktx.html