自己开发实现OAuth做webapi认证

一、作为认证服务器,首先需要提供一个可以通过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();
        }
}

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

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

上文可以看到,在生成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));
        }

为什么要用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);
            }
        }
    }

使用比较传统的方式,继承于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;
        }

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

时间: 2024-08-28 18:55:47

自己开发实现OAuth做webapi认证的相关文章

使用OAuth打造webapi认证服务供自己的客户端使用

一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.注意是Authorization(授权),而不是Authentication(认证).用来做Authentication(认证)的标准叫做openid connect,我们将在以后的文章中进行介绍. 二.名词定义 理解OAuth中的专业术语能够帮助你理解其流程模式,OAuth中常用的名词术语有4个,为了便于理解这些术语,我们先假设一个很常见的授权场景: 你访问了一个日志网站(thir

OAuth在WebApi中的使用,前后台分离的调用方式

前段时间由于公司架构服务层向WebApi转换,就研究了OAuth在WebApi中的使用,这中间遇到了很多坑,在此记录一下OAuth的正确使用方式. 1.  OAuth是做什么的? 在网上浏览时,大家都见过这样的功能:网站A提供了第三方登录服务,比如使用新浪微博.QQ账户登录.用户使用第三方账户登陆后,第三方返回Token给网站A,当网站A调用第三方服务请求登录用户信息时需传递该Token给第三方,第三方才允许该服务请求.之后的每次请求无需再次认证,直接使用该Token即可.这就是OAuth的典型

使用OAuth打造webapi认证服务供自己的客户端使用(转)

转自:http://www.cnblogs.com/richieyang/p/4918819.html#!comments 一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.注意是Authorization(授权),而不是Authentication(认证).用来做Authentication(认证)的标准叫做openid connect,我们将在以后的文章中进行介绍. 二.名词定义 理解OAuth中的专业术语能够帮助你理解其流程模

Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解

用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息经过处理之后会保存在cookie.缓存.Session等地方,然后还有一个过期时间,避免每次都要去捞数据库.在node下基本上也是这个思路,这一节的内容会涉及到user模型的加密方式.如何生成一个Json Web Token(JWT).以及在客户端用Angular创建注册和登录页面,在请求需要认证的

OAuth打造webapi认证服务

使用OAuth打造webapi认证服务供自己的客户端使用 一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.注意是Authorization(授权),而不是Authentication(认证).用来做Authentication(认证)的标准叫做openid connect,我们将在以后的文章中进行介绍. 二.名词定义 理解OAuth中的专业术语能够帮助你理解其流程模式,OAuth中常用的名词术语有4个,为了便于理解这些术语,我们先

使用OAuth打造webapi认证服务供自己的客户端使用(二)

在上一篇”使用OAuth打造webapi认证服务供自己的客户端使用“的文章中我们实现了一个采用了OAuth流程3-密码模式(resource owner password credentials)的WebApi服务端.今天我们来实现一个js+html版本的客户端. 一.angular客户端 angular版本的客户端代码来自于http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-

OAuth 2.0 认证授权

其实之前自己做的微信服务号的绑定登录也就是个OAuth认证授权 简单看下第三方使用OAuth做认证授权的过程:(取自网络,带图的大家应该都喜欢~) 第一步:用户登录第三方网站,例如使用qq登录. 第二步:点击登录后,会跳到qq平台提示输入用户名和密码. 第三步:如果用户名和密码正确,会提示是否接受授权,如果授权成功,第三方网站就能访问你的资源了,qq头像.用户名等 认证和授权过程(包括三方) 1.服务提供方,用户使用服务提供方来存储受保护的资源,如照片,视频,联系人列表. 2.用户,存放在服务提

OAuth 2.0 认证的原理与实践

摘要: 使用 OAuth 2.0 认证的的好处是显然易见的.你只需要用同一个账号密码,就能在各个网站进行访问,而免去了在每个网站都进行注册的繁琐过程. 本文将介绍 OAuth 2.0 的原理,并基于 Spring Security 和 GitHub 账号,来演示 OAuth 2.0 的认证的过程. 原文同步至https://waylau.com/principle-and-practice-of-oauth2/ 使用 OAuth 2.0 认证的的好处是显然易见的.你只需要用同一个账号密码,就能在

想自学软件开发要怎么做

随着科技的发展,it行业是越来越好,很多其他行业的从业者看到了it行业的发展后,都纷纷想转行到it.但是由于对it行业的不了解,也都只是有想法,并没有真正过来.也有人想通过自学it后转行进来,比如自学软件开发的,想一边工作的同时一边自学软件开发.想自学软件开发要怎么做 一. 多看书,看好书 看一本好书比看10本其他书不适合书都要来的好,而看书就是打基础的过程,这个过程看似简单,不重要.但其实这个过程才是关键,这一步没做好,后面的学习只会越来越辛苦,到最后学不下去都是可能的.建议初学者和自学软件开