欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

asp.net core2.2 多用户验证和授权

程序员文章站 2022-04-24 13:18:38
asp.net core2.2 "用户验证" 和 "授权" 有很详细和特贴心的介绍,我感兴趣的主要是这两篇: 1. "cookie身份验证" 2. "基于角色的授权" 我的项目有两类用户: 1. 微信公众号用户,用户名为公众号的openid 2. 企业微信的用户,用户名为企业微信的userid 每类 ......

asp.net core2.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运行,截屏如下:
asp.net core2.2 多用户验证和授权

asp.net core2.2 多用户验证和授权

asp.net core2.2 多用户验证和授权

asp.net core2.2 多用户验证和授权

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


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

    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,如何有?