• ASP.NET Core2.2 多用户验证和授权


    asp.net core2.2 用户验证授权有很详细和特贴心的介绍,我感兴趣的主要是这两篇:

    1. cookie身份验证
    2. 基于角色的授权

    我的项目有两类用户:

    1. 微信公众号用户,用户名为公众号的openid
    2. 企业微信的用户,用户名为企业微信的userid

    每类用户中部分人员具有“Admin”角色

    因为企业微信的用户有可能同时是微信公众号用户,即一个人两个名,所以需要多用户验证和授权。咱用代码说话最简洁,如下所示:

    public class DemoController : Controller
    {
        /// <summary>
        /// 企业微信用户使用的模块
        /// </summary>
        /// <returns></returns>
        public IActionResult Work()
        {
            return Content(User.Identity.Name +User.IsInRole("Admin"));
        }
        /// <summary>
        /// 企业微信管理员使用的模块
        /// </summary>
        /// <returns></returns>
        public IActionResult WorkAdmin()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
        /// <summary>
        /// 微信公众号用户使用的模块
        /// </summary>
        /// <returns></returns>
        public IActionResult Mp()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
        /// <summary>
        /// 微信公众号管理员使用的模块
        /// </summary>
        /// <returns></returns>
        public IActionResult MpAdmin()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
    }
    

    下面咱一步一步实现。

    第一步 改造类Startup

    1. 修改ConfigureServices方法,加入以下代码

           services.AddAuthentication
               (
               "Work"  //就是设置一个缺省的cookie验证的名字,缺省的意思就是需要写的时候可以不写。另外很多时候用CookieAuthenticationDefaults.AuthenticationScheme,这玩意就是字符串常量“Cookies”,
               )
               .AddCookie
               (
               "Work", //cookie验证的名字,“Work”可以省略,因为是缺省名
               option =>
               {
                   option.LoginPath = new PathString("/Demo/WorkLogin"); //设置验证的路径
                   option.AccessDeniedPath= new PathString("/Demo/WorkDenied");//设置无授权访问跳转的路径
               }).AddCookie("Mp", option =>
               {
                   option.LoginPath = new PathString("/Demo/MpLogin");
                   option.AccessDeniedPath = new PathString("/Demo/MpDenied");
               });
      
    2. 修改Configure方法,加入以下代码

           app.UseAuthentication();
      

    第二步 添加验证

        public async Task WorkLogin(string returnUrl)
        {
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "UserId"),
                new Claim(ClaimTypes.Role, "Admin") //如果是管理员
            };
    
            var claimsIdentity = new ClaimsIdentity(claims, "Work");//“,"Work"”可以省略,因为是缺省名
    
            var authProperties = new AuthenticationProperties
            {
                AllowRefresh = true,
                //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10), 
                // The time at which the authentication ticket expires. A 
                // value set here overrides the ExpireTimeSpan option of 
                // CookieAuthenticationOptions set with AddCookie.
                IsPersistent = false, //持久化保存,到底什么意思我也不太清楚,哪位兄弟清楚的话,盼解释
                //IssuedUtc = <DateTimeOffset>,
                // The time at which the authentication ticket was issued.
                RedirectUri = returnUrl ?? "/Demo/Work"
            };
    
            await HttpContext.SignInAsync("Work", new ClaimsPrincipal(claimsIdentity), authProperties);
        }
        public IActionResult WorkDenied()
        {
            return Forbid();
        }
    
    
        public async Task MpLogin(string returnUrl)
        {
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "OpenId"),
                new Claim(ClaimTypes.Role, "Admin") //如果是管理员
            };
    
            var claimsIdentity = new ClaimsIdentity(claims, "Mp");//“,"Mp"”不能省略,因为不是缺省名
    
            var authProperties = new AuthenticationProperties
            {
                AllowRefresh = true,
                IsPersistent = false,
                RedirectUri = returnUrl ?? "/Demo/Mp"
            };
    
            await HttpContext.SignInAsync("Mp", new ClaimsPrincipal(claimsIdentity), authProperties);
        }
        public IActionResult MpDenied()
        {
            return Forbid();
        }
    

    第三步 添加授权

    就是在对应的Action前面加[Authorize]

        /// <summary>
        /// 企业微信用户使用的模块
        /// </summary>
        /// <returns></returns>
        [Authorize(
            AuthenticationSchemes ="Work" //缺省名可以省略
            )]
        public IActionResult Work()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
        /// <summary>
        /// 企业微信管理员使用的模块
        /// </summary>
        /// <returns></returns>
        [Authorize(AuthenticationSchemes ="Work",Roles ="Admin")]
        public IActionResult WorkAdmin()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
        /// <summary>
        /// 微信公众号用户使用的模块
        /// </summary>
        /// <returns></returns>
        [Authorize(AuthenticationSchemes ="Mp")]
        public IActionResult Mp()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
        /// <summary>
        /// 微信公众号管理员使用的模块
        /// </summary>
        /// <returns></returns>
        [Authorize(AuthenticationSchemes ="Mp",Roles ="Admin")]
        public IActionResult MpAdmin()
        {
            return Content(User.Identity.Name + User.IsInRole("Admin"));
        }
    

    Ctrl+F5运行,截屏如下:

    最后,讲讲碰到的坑和求助


    一开始的验证的代码如下:

        public async Task<IActionResult> Login(string returnUrl)
        {
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "UserId"),
                new Claim(ClaimTypes.Role, "Admin") //如果是管理员
            };
    
            var claimsIdentity = new ClaimsIdentity(claims, "Work");//“,"Work"”可以省略,因为是缺省名
    
            var authProperties = new AuthenticationProperties
            {
                //AllowRefresh = true,
                //IsPersistent = false,
                //RedirectUri 
            };
    
            await HttpContext.SignInAsync("Work", new ClaimsPrincipal(claimsIdentity), authProperties);
    
            return Content("OK");
        }
    
    1. 返回类型为Task<IActionResult> ,因为懒得写View,顺手写了句return Content("OK");
    2. 从网站复制过来代码,AuthenticationProperties没有设置任何内容

    运行起来以后不停的调用login,百度了半天,改了各种代码,最后把return Content("OK");改成return RedirectToAction("Index");一切OK!

    揣摩原因可能是当 return Content("OK");时,自动调用AuthenticationPropertiesRedirectUri,而RedirectUri为空时,自动调用自己。也不知道对不对。

    这时候重视起RedirectUri,本来就要返回到returnUrl,是不是给RedirectUri赋值returnUrl就能自动跳转?

    确实,return Content("OK");时候自动跳转了,return RedirectToAction("Index");无效。

    最后把Task<IActionResult> 改成Task ,把return ...删除,一切完美!(弱弱问一句,是不是原来就应该这样写?我一直在走弯路?)

    求助

    User有属性Identities,看起来可以有多个Identity,如何有?

  • 相关阅读:
    公众号开发完整页面2
    公众号开发完整页面1
    公众号开发15【html页面】
    公众号开发【分享功能】
    公众号开发13【生成二维码】
    公众号开发11【模板消息接口】
    ST05 跟踪SQL
    ABAP 动态生成内表的几种方法
    SMARTFORM & SAPScript
    某种业务场景下,将一个工作区的多个字段整理到一个内表中
  • 原文地址:https://www.cnblogs.com/catzhou/p/10243069.html
Copyright © 2020-2023  润新知