ASP.NET Core-Cookie-based认证的实现

 cookie认证方式如下图所示,当我们访问一个网页(Admin/Index)时候,这时候系统会检查你是否有权限,假如没有权限,便会我当前Url重定向到登陆页面(/Account/Login),在登陆成功后,系统会返回一个cookie保存在浏览器,此时再带

着这个cookie去重新访问你最开始要访问的页面(Admin/Index)。

我们在.net core 中,也有一套基于cookie-basic的认证方式。

配置文件:

  "CookieOptions": {
    "CookieName": "Authentication",
    "CookieDomain": "xxxxxx.com", 
    "CookieTimeout": "28800",
    "CookieLoginUrl": "/Auth/Login",
    "CookieLogoutUrl": "/Auth/Logout",
    "CookieDeniedUrl": "/Auth/Forbidden",
    "CookieReturnUrlParameter": "returnUrl",
    "CookieIsessential": true
  }

ConfigureService方法中添加:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(o => {
                    var cookieOptions = Configuration.GetSection("CookieOptions").Get<CookieOptions>();

                    o.LoginPath = cookieOptions.CookieLoginUrl;//登录路径:这是当用户试图访问资源但未经过身份验证时,程序将会将请求重定向到这个相对路径。
                    o.LogoutPath = cookieOptions.CookieLogoutUrl;
                    o.AccessDeniedPath = cookieOptions.CookieDeniedUrl;
                    o.ReturnUrlParameter = cookieOptions.CookieReturnUrlParameter ?? "returnUrl";
                    double timeOut = Convert.ToDouble(cookieOptions.CookieTimeout ?? "28880");
                    o.ExpireTimeSpan = System.TimeSpan.FromSeconds(timeOut);
                    o.Cookie.HttpOnly = true;
                    o.Cookie.Name = cookieOptions.CookieName;
                    o.Cookie.Domain = cookieOptions.CookieDomain;
                    o.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax;
                    o.Cookie.Path = "/";
                    o.Cookie.IsEssential = Convert.ToBoolean(cookieOptions.CookieIsessential ?? "true");//是否强制存储cookie,注意,也就是当用户不同意使用cookie的时候,你也可以通过设置这个属性为true把cookie强制存储.
                    o.SlidingExpiration = true;//Cookie可以分为永久性的和临时性的。 临时性的是指只在当前浏览器进程里有效,浏览器一旦关闭就失效(被浏览器删除)。 永久性的是指Cookie指定了一个过期时间,在这个时间到达之前,此cookie一直有效(浏览器一直记录着此cookie的存在)。 slidingExpriation的作用是,指示浏览器把cookie作为永久性cookie存储,但是会自动更改过期时间,以使用户不会在登录后并一直活动,但是一段时间后却自动注销。也就是说,你10点登录了,服务器端设置的TimeOut为30分钟,如果slidingExpriation为false,那么10:30以后,你就必须重新登录。如果为true的话,你10:16分时打开了一个新页面,服务器就会通知浏览器,把过期时间修改为10:46。 更详细的说明还是参考MSDN的文档。
                    o.Events = new CookieAuthenticationEvents
                    {
                        OnSignedIn = context =>
                        {
                            return Task.CompletedTask;
                        },
                        OnSigningOut = context =>
                        {
                            return Task.CompletedTask;
                        },
                        OnValidatePrincipal = context =>
                        {
                            return Task.CompletedTask;
                        },
                    };
                });

Configure方法中添加:

app.UseAuthentication();

助手类:

public class DefaultFormsAuthentication
    {
        /// <summary>
        /// 设置登录Cookie
        /// https://www.cnblogs.com/savorboard/p/authentication.html
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="userPrincipal">登录人的用户身份证信息(身份证当事人)</param>
        /// <returns></returns>
        public static Task SetAuthCookieAsync(HttpContext httpContext, ClaimsPrincipal userPrincipal)
        {
            return httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal);
        }
        /// <summary>
        /// 设置登录Cookie
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="userPrincipal">登录人的用户身份证信息(身份证当事人)</param>
        /// <param name="authenticationProperties">授权属性信息</param>
        /// <returns></returns>
        public static Task SetAuthCookieAsync(HttpContext httpContext, ClaimsPrincipal userPrincipal, AuthenticationProperties authenticationProperties)
        {
            //登入操作
            return httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, authenticationProperties);
        }

        /// <summary>
        /// 设置登录Cookie
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="userPrincipal">登录人的用户身份证信息(身份证当事人)</param>
        /// <param name="expireTimeSpan">Cookie过期时间</param>
        /// <returns></returns>
        public static Task SetAuthCookieAsync(HttpContext httpContext, ClaimsPrincipal userPrincipal, TimeSpan expireTimeSpan)
        {
            //登入操作
            if (expireTimeSpan > TimeSpan.Zero)
            {
                return SetAuthCookieAsync(
                                            httpContext
                                            , userPrincipal
                                            , new AuthenticationProperties
                                            {
                                                ExpiresUtc = DateTimeOffset.UtcNow.Add(expireTimeSpan),
                                                IsPersistent = true,//若要创建持久 cookie,则还必须设置IsPersistent
                                                AllowRefresh = true,
                                            }
                                        );
            }
            else
            {
                return SetAuthCookieAsync(httpContext, userPrincipal);
            }
        }
        /// <summary>
        /// 设置登录Cookie
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="authUser">登录用户信息</param>
        /// <param name="expireTimeSpan">指定Cookie的过期时间</param>
        /// <returns></returns>
        public static Task SetAuthCookieAsync(HttpContext httpContext, LoginModel authUser, TimeSpan expireTimeSpan)
        {
            // 身份证当事人
            ClaimsPrincipal userPrincipal = AuthenticationTicketBuilder.CreateAuthenticationTicket(authUser);
            //当事人登录
            return SetAuthCookieAsync(httpContext, userPrincipal, expireTimeSpan);
        }
        /// <summary>
        /// 设置登录Cookie
        /// 默认使用全局ExpireTimeSpan设置的过期时间
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="authUser">登录用户信息</param>
        /// <returns></returns>
        public static Task SetAuthCookieAsync(HttpContext httpContext, LoginModel authUser)
        {
            // 身份证当事人
            ClaimsPrincipal userPrincipal = AuthenticationTicketBuilder.CreateAuthenticationTicket(authUser);
            //当事人登录
            return SetAuthCookieAsync(httpContext, userPrincipal);
        }

        /// <summary>
        /// 设置JWT格式的登录Cookie
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="authUser">登录用户信息</param>
        /// <param name="jwtTokenGenerator">JWT Token生成器</param>
        /// <returns></returns>
       /* public static Task SetJwtAuthCookieAsync(HttpContext httpContext, LoginModule authUser, IJwtTokenGenerator jwtTokenGenerator)
        {
            return SetJwtAuthCookieAsync(httpContext, authUser, jwtTokenGenerator, TimeSpan.Zero);
        }*/
        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="authUser"></param>
        /// <param name="jwtTokenGenerator"></param>
        /// <param name="expireTimeSpan"></param>
        /// <returns></returns>
       /* public static Task SetJwtAuthCookieAsync(HttpContext httpContext, LoginModule authUser, IJwtTokenGenerator jwtTokenGenerator, TimeSpan expireTimeSpan)
        {
            //创建登录用户身份单元项集合
            var claimList = AuthenticationTicketBuilder.CreateClaimList(authUser);
            //身份证当事人
            TokenWithClaimsPrincipal tokenWithClaimsPrincipal = jwtTokenGenerator.GenerateAccessTokenWithClaimsPrincipal(claimList);
            if (expireTimeSpan > TimeSpan.Zero)
            {
                tokenWithClaimsPrincipal.AuthenticationProperties.ExpiresUtc = CalculateCookieExpirationDate(expireTimeSpan);
            }
            //当事人登录
            return SetAuthCookieAsync(httpContext, tokenWithClaimsPrincipal.ClaimsPrincipal, tokenWithClaimsPrincipal.AuthenticationProperties);
        }*/
        /// <summary>
        /// 退出登录
        /// </summary>
        public static Task Signout(HttpContext httpContext)
        {
            //登出操作
            return httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }


        #region net core 关于 cookie 序列化,加密,编码的方法
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static byte[] Serialize(AuthenticationTicket data)
        {
            return TicketSerializer.Default.Serialize(data);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static AuthenticationTicket Deserialize(byte[] data)
        {
            return TicketSerializer.Default.Deserialize(data);
        }
        /// <summary>
        /// 获取登录用户票据信息(密文)
        /// https://www.cnblogs.com/savorboard/p/dotnetcore-data-protection.html
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="plainTicket"></param>
        /// <returns></returns>
        public static string Encrypt(IDataProtector provider, string plainTicket)
        {
            return provider.Protect(plainTicket);
        }
        public static byte[] Encrypt(IDataProtector provider, byte[] plainTicket)
        {
            return provider.Protect(plainTicket);
        }
        /// <summary>
        /// 获取登录用户票据信息(明文)
        /// https://www.cnblogs.com/savorboard/p/dotnetcore-data-protection.html
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="encryptedTicket"></param>
        /// <returns></returns>
        public static string Decrypt(IDataProtector provider, string encryptedTicket)
        {
            return provider.Unprotect(encryptedTicket);
        }
        public static byte[] Decrypt(IDataProtector provider, byte[] encryptedTicket)
        {
            return provider.Unprotect(encryptedTicket);
        }
        public static string Encode(byte[] data)
        {
            return Base64UrlTextEncoder.Encode(data);
        }
        public static byte[] Decode(string text)
        {
            return Base64UrlTextEncoder.Decode(text);
        }
        #endregion
    }


 public class AuthenticationTicketBuilder
    {
        /// <summary>
        /// 创建登录用户的身份单元项集合
        /// </summary>
        /// <param name="authUser">登录用户信息</param>
        /// <returns>返回登陆用户的身份单元项集合</returns>
        public static List<Claim> CreateClaimList(LoginModel authUser)
        {
            //身份单元项项集合
            List<Claim> claimList = new List<Claim>()
                    {
                        new Claim(type: ClaimTypes.Email, value: authUser.Email), //身份单元项
                        new Claim(type: ClaimTypes.Name, value: authUser.RealName),
                        new Claim(type: ClaimTypes.NameIdentifier, value: authUser.ID.ToString()),
                        new Claim(type: ClaimTypes.Role, value: authUser.ClientID ?? string.Empty),
                    };
            return claimList;
        }
        /// <summary>
        /// 创建登陆用户的票据信息
        /// </summary>
        /// <param name="authUser">登录用户信息</param>
        /// <returns>返回登录用户的用户身份证信息(身份证当事人)</returns>
        public static ClaimsPrincipal CreateAuthenticationTicket(LoginModel authUser)
        {
            List<Claim> claimList = CreateClaimList(authUser);//身份单元项集合
            return CreateAuthenticationTicket(claimList);
        }
        /// <summary>
        /// 创建登陆用户的票据信息
        /// </summary>
        /// <param name="claimList">登陆用户的身份单元项集合</param>
        /// <returns>返回登录用户的用户身份证信息(身份证当事人)</returns>
        public static ClaimsPrincipal CreateAuthenticationTicket(IEnumerable<Claim> claimList)
        {
            ClaimsIdentity userIdentity = new ClaimsIdentity(claimList, "ticket");//身份证
            ClaimsPrincipal userPrincipal = new ClaimsPrincipal(userIdentity);//身份证当事人
            return userPrincipal;
        }
    }
View Code

LoginModel配置类:

public class LoginModel
    {
        public LoginModel() { }
        public LoginModel(string returnUrl)
        {
            this.ReturnUrl = returnUrl;
        }
        public LoginModel(string email, string password)
        {
            this.Email = email;
            this.Password = password;
        }
        public LoginModel(string email, string password, string returlUrl) : this(email, password)
        {
            this.ReturnUrl = returlUrl;
        }
        public int ID { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }

        public string ReturnUrl { get; set; }
        public string ClientID { get; set; }
        public string RealName { get; set; }
    }
View Code

客户端:

//判断登录
_httpContext.User.Identity.IsAuthenticated;

//设置登录 
DefaultFormsAuthentication.SetAuthCookieAsync(this._httpContext, new LoginModel
                {
                    ClientID = userInfo.UserID.ToString(),
                    Email = "[email protected]",
                    ID = "1",
                    Password = string.Empty,
                    RealName = "fan",
                    ReturnUrl = string.Empty,
                });

111

猜你喜欢

转载自www.cnblogs.com/fanfan-90/p/12395700.html