你的位置:首页 > ASP.net教程

[ASP.net教程]自己开发实现OAuth做webapi认证


看到园子里面有人写的OAuth,就想把自己实现的OAuth也分享一下,关于OAuth协议这里就不再赘述。

一、作为认证服务器,首先需要提供一个可以通过appid/appsecret来获取token这样的一个接口,于是便有了以下代码。

  public class AuthController : ApiController  {    [HttpGet]    public HttpResponseMessage Token(string appid = "", string appsecret = "")    {      ApiResponseEntity rep;      var isv = AppManage.Instance.GetAppISV(appid, appsecret);      if (isv != null)      {        string token = TokenManage.Instance.CreateToken(appid);        rep = new ApiResponseEntity        {          Status = InterfaceStatus.Success,          BizData = new          {            AccessToken = token          }        };      }      else      {        rep = new ApiResponseEntity()        {          Status = InterfaceStatus.Parm_Missing,          Message = "param error"        };      }      return rep.ToHttpResponseMessage();    }}

View Code

创建token的算法可以自行实现,我是将新生成的Guid做了一下md5处理,代码如下:

public string CreateToken(string appid)    {      string token = Guid.NewGuid().ToString().ToMd5();      Set(token, appid);      return token;    }

View Code

上文可以看到,在生成token了以后,就一个SetToken,就是将token存储在缓存里面,并设置了一定时间的生存周期,代码如下:

public void Set(string token, string appid)    {      var config = ServerConfigManage.Instance.GetServerConfig();      string key = string.Format(RedisCacheKey.App_Token, token);      RedisNetHelper.Set<string>(key, appid, DateTime.Now.AddSeconds(config.TokenSurvivalTime));    }

View Code

为什么要用token做key,是因为token的变更会导致isv token验证失效,但是用token做key就可以在存活周期内,这个key都可以使用,避免了多线程获取token,或是其他原因导致的token失效。作为认证服务器,还需要提供一个RefreshToken这样的接口,用来给刷新token的存活周期,代码相似这里就不再赘述。

 

二、在Api做验证的时候,就需要开始对Token进行验证了,代码如下:

 public class OAuthHandler : DelegatingHandler  {    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)    {      ApiResponseEntity repEntity = null;      string appid = "";      string ip = RequestHelper.GetWebClientIp();      if (!OAuthValidate.IpValidate(ip))      {        repEntity = new ApiResponseEntity        {          Status = InterfaceStatus.IllegalIp,          Message = "ip access limit"        };      }      else      {        string token = "";        string url = request.RequestUri.AbsoluteUri;        var routeData = request.GetRouteData();        string controller = routeData.Values["controller"].ToString().ToLower();        string action = routeData.Values["action"].ToString().ToLower();        if (controller.Equals("auth") && action.Equals("token"))        {          return base.SendAsync(request, cancellationToken);        }        if (request.Method == HttpMethod.Get)        {          var query = request.RequestUri.ParseQueryString();          token = query["token"];        }        if (token == null || token.Length == 0)        {          repEntity = new ApiResponseEntity          {            Status = InterfaceStatus.Token_Faild,            Message = "token invalid"          };        }        else        {          appid = TokenManage.Instance.Get(token);          if (appid == null || appid.Length == 0)          {            repEntity = new ApiResponseEntity            {              Status = InterfaceStatus.Token_Faild,              Message = "token invalid"            };          }          else          {            if (!OAuthValidate.ApiValidate              (              string.Format("{0}/{1}", controller, action),              appid              ))            {              repEntity = new ApiResponseEntity              {                Status = InterfaceStatus.No_Access,                Message = "api access limit"              };            }          }        }      }      if (repEntity != null)      {        var tsc = new TaskCompletionSource<HttpResponseMessage>();        tsc.SetResult(repEntity.ToHttpResponseMessage());        return tsc.Task;      }      else      {        return base.SendAsync(request, cancellationToken);      }    }  }

View Code

使用比较传统的方式,继承于DelegatingHandler,然后进行处理,首先是做的IP验证,然后再进行token有效期验证,最后再进行Api的权限调用验证。验证的代码如下:

 public static bool IpValidate(string ip)    {      var config = ServerConfigManage.Instance.GetServerConfig();      bool isPass = true;      if (isPass && config.IsStartIpWhiteList)      {        isPass = config.IpWhiteList.Contains(ip);      }      if (isPass && config.IsStartIpBlackList)      {        isPass = !config.IpBlackList.Contains(ip);      }      return isPass;    }    public static bool ApiValidate(string api, string appid)    {      var config = ServerConfigManage.Instance.GetServerConfig();      if (config.IsStartApiControl)      {        var apis = AppManage.Instance.GetAppApiResource(appid);        return apis != null && apis.Contains(api);      }      return true;    }

View Code

GetServerConfig()是从DB/Cache里面获取服务器的自定义配置,然后看是否开启ip白名单/黑名单,下面的代码同理,是否开启权限验证。

那认证服务器到这里实际上就结束了,关于isv申请appid/appsecret。然后用户同意授权以后,存储appid和user之间的关联关系,就需要看客自行实现了。

 

另外有一个扩展代码这里也提一下,就是关于ApiResponseEntity的返回值处理,代码如下:

public static HttpResponseMessage ToHttpResponseMessage(this ResponseEntity rep, bool isEncrypt = false)    {      return new HttpResponseMessage(HttpStatusCode.OK)      {        Content = new StringContent          (          isEncrypt          ? EncryptHelper.Base64Replace(EncryptHelper.AESEncryptBase64(JsonHelper.ToJson(rep), Config.ApiEncryptKey))          : JsonHelper.ToJson(rep),           System.Text.Encoding.UTF8,          "application/json"          )      };    }

View Code