• asp.net core的cookie认证


    以前都是重复造轮子,最近研究asp.net core的认证和授权,用起来还是很方便的。

    配置类:

    using Auth.Core.ComponentExtensions;
    using Auth.Core.Configuration;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.Extensions.DependencyInjection;
    namespace Auth.Core.ServiceExtensions
    {
        public static class CookieAuthenticationService
        {
            /// <summary>
            /// 注册常用的工具帮助类
            /// </summary>
            /// <param name="services"></param>
            public static void AddCookieAuthenticationService(this IServiceCollection services)
            {
                GlobalConfig globalConfig = GlobalVars.GlobalConfig;
                //身份认证
                services.AddAuthentication(options =>
                {
                    //只配置了DefaultScheme,这样,DefaultSignInScheme, DefaultSignOutScheme, DefaultChallengeScheme, DefaultForbidScheme 等都会使用该 Scheme 作为默认值
                    //注意新版本必须设置,否则会报错
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie(options =>
                {
                    options.Cookie.Name = globalConfig.AuthConfig.CookieName;
                    //设置了HttpOnly避免XSS攻击。
                    options.Cookie.HttpOnly = true;
                    options.Cookie.Domain = globalConfig.AuthConfig.CookieDomain;
                    options.ExpireTimeSpan = System.TimeSpan.FromSeconds(globalConfig.AuthConfig.ExpireTime); //authenticationPropertie中的设置时间优先
                    //options.ReturnUrlParameter = "abc";
                    //options.LoginPath = new PathString("/Account/Login");
                    //options.AccessDeniedPath = new PathString("/Account/Denied");
                    //options.LogoutPath = new PathString("/Account/Logout");
                    options.Cookie.Path = "/";
                    options.TicketDataFormat = new TicketDataFormat(new AesDataProtector(globalConfig.AuthConfig.SecurityKey));
                    options.SlidingExpiration = true; //是否平滑过期
                    options.Events = new CookieAuthenticationEvents
                    {
                        ///自定义验证事件
                        //OnValidatePrincipal = CustomCookieAuthenticationEvents.OnValidateAsync,
                        //未登录跳转事件
                        OnRedirectToLogin = CustomCookieAuthenticationEvents.OnRedirectToLogin,
                        //无权限跳转事件
                        OnRedirectToAccessDenied = CustomCookieAuthenticationEvents.OnRedirectToAccessDenied,
                        ////签发前的事件
                       OnSigningIn = CustomCookieAuthenticationEvents.OnSigningIn,
                    };
    
                    // 在这里可以根据需要添加一些Cookie认证相关的配置,在本次示例中使用默认值就可以了。
                });
    
            }
    
        }
    
    }

    这里重定义了加密方式:options.TicketDataFormat = new TicketDataFormat(new AesDataProtector(globalConfig.AuthConfig.SecurityKey)); 默认的加密方式太长了。

    加密类代码如下:

    using HuaTuo.Utils;
    using Microsoft.AspNetCore.DataProtection;
    
    namespace Auth.Core.ServiceExtensions
    {
        internal class AesDataProtector : IDataProtector
        {
            private string _key;
            public AesDataProtector(string key)
            {
                this._key = key;
            }
            public IDataProtector CreateProtector(string purpose)
            {
                return this;
            }
            /// <summary>
            /// 只对Claim中的CustomSerializationData属性行了保护,并非整个ClaimsPrincipal对象
            /// </summary>
            /// <param name="plaintext"></param>
            /// <returns></returns>
            public byte[] Protect(byte[] plaintext)
            {
                string text=System.Text.Encoding.UTF8.GetString(plaintext);
                string enText ="";
                try
                {
                    enText = AESHelper.Encrypt(text, this._key);
                }
                catch
                {
                }
                return System.Text.Encoding.UTF8.GetBytes(enText);
            }
    
            public byte[] Unprotect(byte[] protectedData)
            {
                string text = System.Text.Encoding.UTF8.GetString(protectedData);
                string deText ="";
                try
                {
                    deText = AESHelper.Decrypt(text, this._key);
                }
                catch
                {
                }
                return System.Text.Encoding.UTF8.GetBytes(deText);
            }
        }
    }

    这里采用了aes对称加密,AESHelper为工具类提供的帮助类,这里就不提供了。

    下面是自定义时间类,默认的没有认证通过会进行页面跳转,对于前后端分离项目是很不友好的,所以重定义对自带的几个event进行了自定义。

                    options.Events = new CookieAuthenticationEvents
                    {
                        ///自定义验证事件
                        //OnValidatePrincipal = CustomCookieAuthenticationEvents.OnValidateAsync,
                        //未登录跳转事件
                        OnRedirectToLogin = CustomCookieAuthenticationEvents.OnRedirectToLogin,
                        //无权限跳转事件
                        OnRedirectToAccessDenied = CustomCookieAuthenticationEvents.OnRedirectToAccessDenied,
                        ////签发前的事件
                       OnSigningIn = CustomCookieAuthenticationEvents.OnSigningIn,
                    };

    自定义事件类代码如下:

    using HuaTuo.Utils;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Http;
    using System;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Auth.Core.ComponentExtensions
    {
        //cookie认证的aop事件
        public class CustomCookieAuthenticationEvents
        {
            /// <summary>
            /// 认证通过后才会进入此任务
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public static  Task OnValidateAsync(CookieValidatePrincipalContext context)
            {
                //TipsInfo tipsInfo = new TipsInfo()
                //{
                //    Status = 0,
                //    Code = StatusCodes.Status401Unauthorized,
                //    Msg = "对不起,你没有权限访问!"
                //};
                //context.Response.ContentType = "application/json";
                //return context.Response.WriteAsync(JsonHelper.JsonParse(tipsInfo), Encoding.UTF8);
                //var userPrincipal = context.Principal;
                //if (userPrincipal?.Identity?.IsAuthenticated??false)
                //{
                //    context.ShouldRenew = true;
                //}
                //else
                //{
                //    context.RejectPrincipal();
                //    //退出,清理cookie
                //    context.HttpContext.SignOutAsync();
                //}
                ////主动删除需要和数据库或redis配合,如用户修改了密码,redis或数据库中插入uid和userPrincipal中的claim进行对比,如果存在则context.RejectPrincipal;
                 return Task.CompletedTask;
            }
    
            ///自定义跳转事件
            public static Task OnRedirectToLogin(RedirectContext<CookieAuthenticationOptions> context)
            {
                //context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                TipsInfo tipsInfo = new TipsInfo()
                {
                    Status = 0,
                    Code = StatusCodes.Status401Unauthorized,
                    Msg = "对不起,未登录或登录超时!"
                };
                context.Response.ContentType = "application/json";
                return context.Response.WriteAsync(JsonHelper.JsonParse(tipsInfo), Encoding.UTF8);
            }
    
            /// <summary>
            /// 签发令牌前的aop,注意:签发到前端的cookie是对密文进行了base64加密
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            internal static Task OnSigningIn(CookieSigningInContext context)
            {
                AuthenticationProperties authenticationProperties = new AuthenticationProperties();
                context.Properties.AllowRefresh =false;//自动刷新cookie
                context.Properties.IssuedUtc = DateTime.UtcNow;//签发时间
                context.Properties.ExpiresUtc = DateTime.UtcNow.Add(context.Options.ExpireTimeSpan);
                context.Properties.IsPersistent = true; //必须设置,否则ExpiresUtc无效
                return Task.CompletedTask;
            }
    
            internal static Task OnRedirectToAccessDenied(RedirectContext<CookieAuthenticationOptions> context)
            {
                var user = context.HttpContext.User.Identity;
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                TipsInfo tipsInfo = new TipsInfo()
                {
                    Status = 0,
                    Code = StatusCodes.Status403Forbidden,
                    Msg = "对不起,您没有权限访问此接口!"
                };
                context.Response.ContentType = "application/json";
                return context.Response.WriteAsync(JsonHelper.JsonParse(tipsInfo), Encoding.UTF8);
            }
        }
    }

    前端登录接口的控制器代码如下:

            [HttpPost]
            public  Task<TipsInfo> GetToken(LoginDto loginDto)
            {
                //通过services层检测用户名密码省略....
    
                AuthConfig authConfig = GlobalVars.GlobalConfig.AuthConfig;
                TipsInfo tipsInfo = new TipsInfo();
    
                    //cookie令牌,签发到前端的cookie对密文又进行了base64加密
                    var claimIdentity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
                    claimIdentity.AddClaim(new Claim("Uid", "1"));
                    claimIdentity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
                    claimIdentity.AddClaim(new Claim(ClaimTypes.Name, "guizhoumen"));
                    claimIdentity.AddClaim(new Claim(ClaimTypes.Email, "email"));
                    claimIdentity.AddClaim(new Claim(ClaimTypes.MobilePhone, "13318250159"));
                    var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
                    // 在OnSigningIn事件中配置后,下面的可以注释掉。
                    //AuthenticationProperties authenticationProperties = new AuthenticationProperties();
                    //authenticationProperties.AllowRefresh = true;//自动刷新cookie
                    //authenticationProperties.IssuedUtc = DateTime.UtcNow;//签发时间
                    //authenticationProperties.ExpiresUtc = DateTime.UtcNow.AddHours(2);
                    //authenticationProperties.IsPersistent = true;
     //HttpContext.SignInAsync(claimsPrincipal, authenticationProperties);
    HttpContext.SignInAsync(claimsPrincipal); return Task.FromResult(tipsInfo); }

    这里需要注意,如果需要设置过期时间,必须定义AuthenticationProperties,而且IsPersistent必须设置为true,AllowRefresh表示自动刷新过期时间。

    这里注释掉,是因为我把这段提到了OnSigningIn时间中去定义了。

  • 相关阅读:
    Windows server 2008设置远程桌面
    .NET高级开发工程师 南通红创软件科技有限公司
    silverlight获取浏览器信息交互数据的方法
    silverlight元素FrameworkElement.LayoutUpdated布局变化事件
    Nicholas C. Zakas如何面试前端工程师
    asp.net自动完成控件在用户控件上失效的解决方法
    构建高性能可扩展ASP.NET网站
    关闭sql server 2005远程连接
    使用asp.net实现单点登陆(SSO)功能
    微软首次展示Windows 8:开始界面类似WP7
  • 原文地址:https://www.cnblogs.com/huaguo/p/15499458.html
Copyright © 2020-2023  润新知