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

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

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

个人项目有两类用户:cookie

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

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

由于企业微信的用户有可能同时是微信公众号用户,即一我的两个名,因此须要多用户验证和受权。咱用代码说话最简洁,以下所示:asp.net

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"));
    }
}

下面咱一步一步实现。async

第一步 改造类Startupide

  1. 修改ConfigureServices方法,加入如下代码visual-studio

    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();

第二步 添加验证.net

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();
    }

第三步 添加受权code

就是在对应的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,如何有?