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

ASP.NET Core 2.0利用Jwt实现授权认证

程序员文章站 2022-11-17 08:37:48
在微服务架构下,一般都会按不同的业务或功能将整个系统切分成不同的独立子系统,再通过REST API或RPC进行通讯并相互调用,形成各个子系统之间的串联结构。在这里,我们将采用REST API的通讯方式。比如: 1、有一个“用户中心”独立子系统名为“Lezhima.UserHub”,是一个基于ASP... ......

背景

在微服务架构下,一般都会按不同的业务或功能将整个系统切分成不同的独立子系统,再通过rest api或rpc进行通讯并相互调用,形成各个子系统之间的串联结构。在这里,我们将采用rest api的通讯方式。

比如:

1、有一个“用户中心”独立子系统名为“lezhima.userhub”,是一个基于asp.net core mvc 2.0的项目。

2、有一个处理用户订单的独立子系统名为“lezhima.userorder”,是一个基于asp.net core webp api 2.0的项目。

3、同时还有一个处理用户文件上传的独立子系统名为“lezhima.userupload”,是一个基于asp.net core webp api 2.0的项目。

业务关系如下:

用户成功登录后进入“lezhima.userhub”,在用户查看订单时通过前端ajax调用“lezhima.userorder”的web api接口,在用户上传图片是通过前端ajax调用“lezhima.userupload”的web api接口。

至此,我们了解了上面的业务关系后,心里一定产生出如下两个问题:

1、如何保障“lezhima.userorder”与“lezhima.userupload”两个独立系统内的web api接口安全,因为它们已经被暴露在了前端。

2、如何在“lezhima.userhub”站颁发token。

那么,带着问题我们下面就结合asp.net core 自带的jwt技术来讨论具体的实现(也许聪明的你有更好的解决方法,请一定告知我,谢谢)。

jwt 全名为:json web token,是一个很成熟的技术,园子里也有很多这方面的知识,我这里就不再重述了。

 

 实现原理

“lezhima.userhub”站因为已经做了登录验证,我们暂且认为它是可信的,所以在前端ajax请求“lezhima.userorder”站的web api接口时先到自已后端去生成一个token,并随之同本次跨站请求一块携带至“lezhima.userorder”站,“lezhima.userorder”站验证请求头中的token是否合法,如合法则继续路由到具体方法中,否则结束请求。“lezhima.userupload”站原理与“lezhima.userorder”相同。

 

实现代码

lezhima.userhub颁发token代码:

        /// <summary>
        /// 颁发一个指定有效期的token,并将当前登录的用户id传递进来		
        /// </summary>
        /// <param name="currentuserid"></param>
        /// <param name="expiresminutes"></param>
        /// <returns></returns>
	  public static async task<string> getaccesstoken(string currentuserid,int expiresminutes=2)
        {
            return await task.run(() =>
            {
				//约定私钥,下面三个参数可放到配置文件中				
                var secret = "nguznmnlnzqtzthkzc00yjrh";
				//发行者
                var iss = "andre";
				//接受者
                var aud = "andre";

                if (string.isnullorempty(secret) || string.isnullorempty(iss) || string.isnullorempty(aud))
                    return "";

                if (string.isnullorempty(currentuserid))
                    currentuserid = guid.newguid().tostring();

                var now = datetime.utcnow;
                var claims = new claim[]
                {
                    new claim(jwtregisteredclaimnames.sub, currentuserid),
                    new claim(jwtregisteredclaimnames.iat, now.touniversaltime().tostring(), claimvaluetypes.integer64)
                };
                var signingkey = new symmetricsecuritykey(encoding.ascii.getbytes(secret));
                var jwt = new jwtsecuritytoken(
                       issuer: iss,
                       audience: aud,
                       claims: claims,
                       notbefore: now,
                       expires: now.add(timespan.fromminutes(expiresminutes)),
                       signingcredentials: new signingcredentials(signingkey, securityalgorithms.hmacsha256)
                 );
                return new jwtsecuritytokenhandler().writetoken(jwt);  //生成一个新的token
            });           
        }

lezhima.userhub前端ajax跨站请求代码:

//封装一个ajax请求公共方法
function getwebdatabyobject(url, requestmethon, paramter) {
    jquery.support.cors = true;
    apiurl = 'http://127.0.0.1:8012/';
    var token = gettoken(); //调用本站内的token颁发web api接口 
    var result = [];
    $.ajax({
        type: requestmethon,
        url: apiurl + url,
        data: paramter,
        async: false,
        beforesend: function (xhr) {
			//将token携带到请求头中
            xhr.setrequestheader("authorization", "bearer " + token);
        },  
        success: function (data) {
            result = data;
        },
        error: function (xmlhttprequest, textstatus, errorthrown) {
            // 状态码
            console.log(xmlhttprequest.status);
            // 状态
            console.log(xmlhttprequest.readystate);
            // 错误信息   
            console.log(textstatus);
        }
    });
    return result;
}

“lezhima.userorder”站开启jwt的token验证,在startup.cs里添加如下代码:

        public iserviceprovider configureservices(iservicecollection services)
        {            
            services.addcors();
			
			//从配置文件中获取私钥、发行者、接受者三个参数
			//三个参数的值必需与颁发token站相同
            var audienceconfig = configuration.getsection("audience");

            var signingkey = new symmetricsecuritykey(encoding.ascii.getbytes(audienceconfig["secret"]));
            var tokenvalidationparameters = new tokenvalidationparameters
            {
                validateissuersigningkey = true,
                issuersigningkey = signingkey,
                validateissuer = true,
                validissuer = audienceconfig["iss"],
                validateaudience = true,
                validaudience = audienceconfig["aud"],
                validatelifetime = true,
                clockskew = timespan.zero,
                requireexpirationtime = true,
            };
			//注入jwt验证
            services.addauthentication(jwtbearerdefaults.authenticationscheme)
                .addjwtbearer(options => {
                    options.requirehttpsmetadata = false;
                    options.tokenvalidationparameters = tokenvalidationparameters;
                });

            services.addmvc();


            var builder = new containerbuilder();
            builder.registermodule(new evolution());
            builder.populate(services);
            var container = builder.build();
            return container.resolve<iserviceprovider>();
        }
        public void configure(iapplicationbuilder app, ihostingenvironment env)
        {
            if (env.isdevelopment())
            {
                app.usedeveloperexceptionpage();
            }
            app.usecors(builder =>
              builder.withorigins("*")
              .allowanyheader()
              .allowanymethod()
              .allowcredentials()
            );         
            //开启验证
            app.useauthentication();
            app.usemvc();
        }

“lezhima.userorder”站内的控制器里添加验证过滤器[authorize],如下代码:

    [route("api/[controller]")]
    //添加过滤器后,该控制器内所有action都将进行token验证
    [authorize]
    public class ordercontroller : controller
    {
        
    }

  

至此,基于asp.net core的jwt跨站验证token方案就全部完成了,是不是很简单呀^_^  ^_^