当前位置: 移动技术网 > IT编程>开发语言>.net > .net core webapi jwt 更为清爽的认证详解

.net core webapi jwt 更为清爽的认证详解

2019年07月18日  | 移动技术网IT编程  | 我要评论

湖南台节目预告,铠甲勇士之炎龙侠小游戏,云乐影城

我的方式非主流,控制却可以更加灵活,喜欢的朋友,不妨花一点时间学习一下

jwt认证分为两部分,第一部分是加密解密,第二部分是灵活的应用于中间件,我的处理方式是将获取token放到api的一个具体的controller中,将发放token与验证分离,token的失效时间,发证者,使用者等信息存放到config中。

1.配置:

在appsettings.json中增加配置

"jwt": {
"issuer": "issuer",//随意定义
"audience": "audience",//随意定义
"secretkey": "abc",//随意定义
"lifetime": 20, //单位分钟
"validatelifetime": true,//验证过期时间
"headfield": "useless", //头字段
"prefix": "prefix", //前缀
"ignoreurls": [ "/auth/gettoken" ]//忽略验证的url
}

2:定义配置类:

internal class jwtconfig
  {
    public string issuer { get; set; }
    public string audience { get; set; }

    /// <summary>
    /// 加密key
    /// </summary>
    public string secretkey { get; set; }
    /// <summary>
    /// 生命周期
    /// </summary>
    public int lifetime { get; set; }
    /// <summary>
    /// 是否验证生命周期
    /// </summary>
    public bool validatelifetime { get; set; }
    /// <summary>
    /// 验证头字段
    /// </summary>
    public string headfield { get; set; }
    /// <summary>
    /// jwt验证前缀
    /// </summary>
    public string prefix { get; set; }
    /// <summary>
    /// 忽略验证的url
    /// </summary>
    public list<string> ignoreurls { get; set; }
  }

3.加密解密接口:

 public interface ijwt
  {
    string gettoken(dictionary<string, string> clims);
    bool validatetoken(string token,out dictionary<string ,string> clims);
  }

4.加密解密的实现类:

install -package system.identitymodel.tokens.jwt

 public class jwt : ijwt
  {
    private iconfiguration _configuration;
    private string _base64secret;
    private jwtconfig _jwtconfig = new jwtconfig();
    public jwt(iconfiguration configration)
    {
      this._configuration = configration;
      configration.getsection("jwt").bind(_jwtconfig);
      getsecret();
    }
    /// <summary>
    /// 获取到加密串
    /// </summary>
    private void getsecret()
    {
      var encoding = new system.text.asciiencoding();
      byte[] keybyte = encoding.getbytes("salt");
      byte[] messagebytes = encoding.getbytes(this._jwtconfig.secretkey);
      using (var hmacsha256 = new hmacsha256(keybyte))
      {
        byte[] hashmessage = hmacsha256.computehash(messagebytes);
        this._base64secret= convert.tobase64string(hashmessage);
      }
    }
    /// <summary>
    /// 生成token
    /// </summary>
    /// <param name="claims"></param>
    /// <returns></returns>
    public string gettoken(dictionary<string, string> claims)
    {
      list<claim> claimsall = new list<claim>();
      foreach (var item in claims)
      {
        claimsall.add(new claim(item.key, item.value));
      }
      var symmetrickey = convert.frombase64string(this._base64secret);
      var tokenhandler = new jwtsecuritytokenhandler();
      var tokendescriptor = new securitytokendescriptor
      {
        issuer = _jwtconfig.issuer,
        audience = _jwtconfig.audience,
        subject = new claimsidentity(claimsall),
        notbefore = datetime.now,
        expires = datetime.now.addminutes(this._jwtconfig.lifetime),
        signingcredentials =new signingcredentials(new symmetricsecuritykey(symmetrickey),
                      securityalgorithms.hmacsha256signature)
      };
      var securitytoken = tokenhandler.createtoken(tokendescriptor);
      return tokenhandler.writetoken(securitytoken);
    }
    public bool validatetoken(string token, out dictionary<string, string> clims)
    {
      clims = new dictionary<string, string>();
      claimsprincipal principal = null;
      if (string.isnullorwhitespace(token))
      {
        return false;
      }
      var handler = new jwtsecuritytokenhandler();
      try
      {
        var jwt = handler.readjwttoken(token);

        if (jwt == null)
        {
          return false;
        }
        var secretbytes = convert.frombase64string(this._base64secret);
        var validationparameters = new tokenvalidationparameters
        {
          requireexpirationtime = true,
          issuersigningkey = new symmetricsecuritykey(secretbytes),
          clockskew = timespan.zero,
          validateissuer = true,//是否验证issuer
          validateaudience = true,//是否验证audience
          validatelifetime = this._jwtconfig.validatelifetime,//是否验证失效时间
          validateissuersigningkey = true,//是否验证securitykey
          validaudience = this._jwtconfig.audience,
          validissuer = this._jwtconfig.issuer
        };
        securitytoken securitytoken;
        principal = handler.validatetoken(token, validationparameters, out securitytoken);
        foreach (var item in principal.claims)
        {
          clims.add(item.type, item.value);
        }
        return true;
      }
      catch (exception ex)
      {
        return false;
      }
    }
  }

5.定义获取token的controller:

在startup.configureservices中注入 ijwt

services.addtransient<ijwt, jwt>(); // jwt注入

[route("[controller]/[action]")]
  [apicontroller]
  public class authcontroller : controllerbase
  {
    private ijwt _jwt;
    public authcontroller(ijwt jwt)
    {
      this._jwt = jwt;
    }
    /// <summary>
    /// gettoken
    /// </summary>
    /// <returns></returns>
    [httppost]
    public iactionresult gettoken()
    {
      if (true)
      {
        dictionary<string, string> clims = new dictionary<string, string>();
        clims.add("username", username);
        return new jsonresult(this._jwt.gettoken(clims));
      }
    }
  }

6.创建中间件:

 public class usejwtmiddleware
  {
    private readonly requestdelegate _next;
    private jwtconfig _jwtconfig =new jwtconfig();
    private ijwt _jwt;
    public usejwtmiddleware(requestdelegate next, iconfiguration configration,ijwt jwt)
    {
      _next = next;
      this._jwt = jwt;
      configration.getsection("jwt").bind(_jwtconfig);
    }
    public task invokeasync(httpcontext context)
    {
      if (_jwtconfig.ignoreurls.contains(context.request.path))
      {
        return this._next(context);
      }
      else
      {
        if (context.request.headers.trygetvalue(this._jwtconfig.headfield, out microsoft.extensions.primitives.stringvalues authvalue))
        {
          var authstr = authvalue.tostring();
          if (this._jwtconfig.prefix.length > 0)
          {
            authstr = authvalue.tostring().substring(this._jwtconfig.prefix.length+1, authvalue.tostring().length -(this._jwtconfig.prefix.length+1));
          }
          if (this._jwt.validatetoken(authstr, out dictionary<string, string> clims))
          {
            foreach (var item in clims)
            {
              context.items.add(item.key, item.value);
            }
            return this._next(context);
          }
          else
          {
            context.response.statuscode = 401;
            context.response.contenttype = "application/json";
            return context.response.writeasync("{\"status\":401,\"statusmsg\":\"auth vaild fail\"}");
          }
        }
        else
        {
          context.response.statuscode = 401;
          context.response.contenttype = "application/json";
          return context.response.writeasync("{\"status\":401,\"statusmsg\":\"auth vaild fail\"}");
        }
      }
    }
  }

7.中间件暴露出去

public static class useusejwtmiddlewareextensions
  {
    /// <summary>
    /// 权限检查
    /// </summary>
    /// <param name="builder"></param>
    /// <returns></returns>
    public static iapplicationbuilder usejwt(this iapplicationbuilder builder)
    {
      return builder.usemiddleware<usejwtmiddleware>();
    }
  }

8.在startup.configure中使用中间件:

app.usejwt();

以1的配置为例:

除了请求 /auth/gettoken 不需要加头信息外,其他的请求一律要求头信息中必须带着

userless:prefix (从auth/gettoken中获取到的token)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网