这个文章先说一说Oauth2.0的原理,再到应用场景,最后才是代码实现,这样才学会最终的思想,并在应用场景使用,所谓实践出真理。

1,Oauth2.0的原理

OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。在互联网,经常用到OAuth2.0无非有三种场景:

1.1对外完全开放,系统与系统的对接,例如淘宝开放平台。

1.2内部系统对内部系统,如:(api.xxxx.com是一个子系统,web.xxxx.com是另外一个业务线的子系统,交给不同的团队处理,有NET,有JAVA)

1.3内部系统对内部客户端系统。如(API.xxxx.com是对外开放的接口系统,IOS,安卓,C/S客户端,相关对接).

综合三种应用场景,我们来分解一下Oauth2.0怎样在实践中使用。

在Oauth2.0的使用场景中,最常见到的就是对外完全开放,像淘宝开放平台,新浪,腾讯QQ,微信,大量使用Oauth2.0,相反,后两种由于都是内部使用,所以一般都存在内部,让我以为Oauth2.0授权模式只有第一种,其实不是,Oauth2.0分别有四种授权模式,分别为:

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

而微信公众号采用的是授权码模式(authorization code),即颁发用户Appid,AppSecret,URL地址合法性,来进行统一调度与验证。,


1.1、授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动,所以一般开放平台首先这一类授权码模式,新浪开放平台,公众号API,淘宝开放平台都采用这一类,一般搭配HTTPS来提高安全机制。

微信公众号API就是采用这一种模式,我们来梳理一下授权码模式的流程:

它的步骤如下:

(A)用户访问客户端,后者将前者导向认证服务器。

(B)用户选择是否给予客户端授权。

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

下面是上面这些步骤所需要的参数。

A步骤中,客户端申请认证的URI,包含以下参数:

  • response_type:表示授权类型,必选项,此处的值固定为"code"
  • client_id:表示客户端的ID,必选项
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

再来看一看微信公众平台OAuth2.0授权详细步骤如下:

1. 用户关注微信公众账号。
2. 微信公众账号提供用户请求授权页面URL。
3. 用户点击授权页面URL,将向服务器发起请求
4. 服务器询问用户是否同意授权给微信公众账号(scope为snsapi_base时无此步骤)
5. 用户同意(scope为snsapi_base时无此步骤)
6. 服务器将CODE通过回调传给微信公众账号
7. 微信公众账号获得CODE
8. 微信公众账号通过CODE向服务器请求Access Token
9. 服务器返回Access Token和OpenID给微信公众账号
10. 微信公众账号通过Access Token向服务器请求用户信息(scope为snsapi_base时无此步骤)
11. 服务器将用户信息回送给微信公众账号(scope为snsapi_base时无此步骤)

是不是一目了然,那么根椐这个需求,整理一下流程为:

1,先去开放平台(api地址)申请一个CODE,(那么我们需要判断appid,请求过来的URL合法性,生成CODE,并附于某个时间有效,5分钟失效,仿微信,然后做持久存储)。

2,再根据CODE,APPID,AppSecret(平台颁发的应用ID及密锁),生成有效期的Access Token。(判断APPID,AppSecret合法性,然后根椐Appid获取持久存储层的Access Token,并把CODE取消合法,然后返回Access Token过期时间)

3,判断Access Token的合法化,完成。

流程梳理完了,我们就开始实现代码的编写:

 /// <summary>
/// 对接商家,开放平台的接口
/// </summary>
/// <param name="AppId">应用ID</param>
/// <param name="RedirectUri">授权回调地址</param>
/// <param name="response_type"></param>
/// <param name="scope"></param>
/// <param name="state"></param>
/// <returns></returns>
[HttpGet]
public dynamic authorize(string AppId, string RedirectUri, string response_type, string scope, string state)
{
//获取APPID应用表的字段
var model = _ISellerApplication.Get(AppId);
//判断APPID合法性及RedirectUri地址的合法
if (model.AppId.Trim().ToLower() == model.AppId.ToLower() && RedirectUri.ToLower().Contains(model.ApplicationUrl.ToLower()))
{ //请求的地址合法性,如果不合法,直接返回
if (!Request.RequestUri.AbsoluteUri.Contains(model.ApplicationUrl.ToLower()))
{
return Redirect($"{RedirectUri}?state={state}");
}
var appcodemodel = new AppCodeModel()
{
AccessToken = string.Concat(Guid.NewGuid().ToString("N"), Guid.NewGuid().ToString("N")).ToLower().CutString(),
AppCode = string.Concat(Guid.NewGuid().ToString("N"), Guid.NewGuid().ToString("N")).ToLower().CutString(),
ApplicationUrl = RedirectUri,
CreateDate = DateTime.Now,
AppId=model.AppId }; //如果插入成功,返回CODE给他们
if (_IAppCode.Insert(appcodemodel))
{
if (RedirectUri.Equals("?"))
{ return Redirect($"{RedirectUri}&state={state}&code={appcodemodel.AppCode}");
}
else
{ return Redirect($"{RedirectUri}?state={state}&code={appcodemodel.AppCode}");}
}
}
//插入不成功,直接返回state
return Redirect($"{RedirectUri}?state={state}");
}

再实现第二步调用:

  /// <summary>
///通过网页授权获取access_token
/// </summary>
/// <param name="AppId"></param>
/// <param name="AppSecret"></param>
/// <param name="code"></param>
/// <param name="grant_type"></param>
/// <returns></returns>
[HttpGet]
public dynamic AccessToken(string AppId, string AppSecret, string code, string grant_type)
{ //从持久层获取APPID模型
var model = _IAppSoft.Get(AppId);
//判断Appid
if (model == null || model.AppId.Trim() != AppId.Trim())
{
return new ApiArgumentException(ApiArgumentExceptionEum.APPID出错.ToString(), (int)ApiArgumentExceptionEum.APPID出错);
}
//判断AppSecret
if (model.AppSecret.Trim() != AppSecret.Trim())
{
return new ApiArgumentException(ApiArgumentExceptionEum.AppSecret错误.ToString(), (int)ApiArgumentExceptionEum.AppSecret错误);
}
//获取CODE并判断,CODE是否在过期范围内,5表示5分钟内有效
var AppCodeModel = _IAppCode.Get(5)); if (AppCodeModel == null)
{
return new ApiArgumentException(ApiArgumentExceptionEum.不合法的oauth_code.ToString(), (int)ApiArgumentExceptionEum.不合法的oauth_code);
}
var apptokenmodel = new AppTokenModel()
{
AccessToken = AppCodeModel.AccessToken,
AppId = AppId,
ClientId = model.ClientId,
CreateDate = DateTime.Now,
ExpireDate = DateTime.Now.AddHours(),
Status =
};
//把AccessToken插入数据库,或者存储缓存
bool bl = _IAppToken.Insert(apptokenmodel);
//返回 AccessToken 及过期时间
return new
{
AccessToken = AppCodeModel.AccessToken,
ExpireDate =
}; }

现在仿微信都完成了授权的核心代码,第二步就可开始写AOP,然后统一验证AccessToken,由于用到的是WEB API2.0,所以我们统一写一个AOP类,并且继承  AuthorizationFilterAttribute, IActionFilter类,即可以写一个简单的AOP

代码如下:

namespace Saas.AOP
{ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class AppOauthAuthentication : AuthorizationFilterAttribute, IActionFilter
{ protected AppTokenModel apptoken; public AppOauthAuthentication() { } public override void OnAuthorization(HttpActionContext actionContext)
{
var query = actionContext.Request.GetParamsFromUrl(); var tokenString = query.Get("accessToken"); if (string.IsNullOrWhiteSpace(tokenString) )
{
actionContext.Response = CreateResponse(actionContext, , "请检查oauth认证参数");
return;
}
apptoken = new AppTokenBusiness().GetByAccessToken(tokenString); if (apptoken == null)
{
actionContext.Response = CreateResponse(actionContext, , "未找到指定的accessToken");
return;
} if (apptoken.ExpireDate < DateTime.Now)
{
actionContext.Response = CreateResponse(actionContext, , "accessToken已过期");
return;
} if (apptoken.Status == )
{
actionContext.Response = CreateResponse(actionContext, , "APPID已更正,当前accessToken已失效");
return;
}
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(apptoken.AppId), null);
base.OnAuthorization(actionContext);
} }}

调用如下:

   /// <summary>
/// 例子
/// </summary> /// <returns></returns>
[HttpPost, AppOauthAuthentication]
public int test()
{
return 1;
}

而简单的一个仿微信的Oauth2.0,就完成了。

而关于Oauth2.0对于内部系统调用,以及APP怎样搭建一个通用的Oauth2.0,在明天再写,结合三种场景,搭建整一套的NET Oauth2.0系统,并完成跨平台。

由于公司项目,是整一套的,暂时没整理实现开放,有需要交流的可以加我微信,BON184195873,扫描以下二维码,备注:CNBLOGS即可以。

NET仿微信Oauth2.0的更多相关文章

  1. 微信OAuth2.0网页受权php

    www.MyException.Cn 网友分享于:2014-01-19 浏览:2504次 微信OAuth2.0网页授权php示例 1.配置授权回调页面域名,如 www.aaa.com 2.模拟公众号的 ...

  2. 解决微信OAuth2.0网页授权回调域名只能设置一个的问题

    https://github.com/HADB/GetWeixinCode GetWeixinCode 解决微信OAuth2.0网页授权回调域名只能设置一个的问题 使用方法 部署get-weixin- ...

  3. 转载:解决微信OAuth2.0网页授权回调域名只能设置一个的问题

    项目地址:https://github.com/HADB/GetWeixinCode 说明:微信项目很多,但是回调域名有限,经常使用,做个笔记. 解决微信OAuth2.0网页授权只能设置一个回调域名的 ...

  4. 微信OAuth2.0网页授权设置一个域名需多个域名使用的问题

    最近遇到一个问题,一个微信公众号,需要在多个域名上使用OAuth2.0网页授权,但微信OAuth2.0网页授权回调域名只能设置一个. 解决办法: 通过多一次的跳转,解决了微信限制回调域名只能设置一个的 ...

  5. 微信OAuth2.0网页授权接口

    微信OAuth2.0网页授权接口 微信OAuth2.0网页授权接口的thinkphp实现版本号.主要实现了oauth网页受权,以及部分其它接口. 用法 为什么用OAuth2.0受权? 通过OAuth2 ...

  6. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-3.微信Oauth2.0交互流程讲解

    笔记 3.微信Oauth2.0交互流程讲解     简介:讲解微信Oauth2.0交互流程              参考:https://open.weixin.qq.com/cgi-bin/sho ...

  7. 微信OAuth2.0网页授权

    1.OAuth2.0网页授权 关于网页授权的两种scope的区别说明 1.以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页 ...

  8. Android 高仿微信6.0主界面 带你玩转切换图标变色

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41087219,本文出自:[张鸿洋的博客] 1.概述 学习Android少不了模仿 ...

  9. 微信Oauth2.0网页开放授权

    网页授权获取用户基本信息 如果用户在微信中(Web微信除外)访问公众号的第三方网页,公众号开发者可以通过此接口获取当前用户基本信息(包括昵称.性别.城市.国家).利用用户信息,可以实现体验优化.用户来 ...

随机推荐

  1. TestNg的xml配置

    TestNG中,可以通过配置xml来运行某一类.包.方法. 1.通过TestNg运行某一个类 <?xml version="1.0" encoding="UTF-8 ...

  2. three.js 源代码凝视(十六)Math/Frustum.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  3. JavaScipt中对DOM的理解

    一.理解DOM 浏览器通过文档对象模型DOM使JavaScript程序可以访问页面上的元素,而DOM是页面上XHTML中文档正文标题.段落.列表.样式ID.class以及所有其他出现的数据的一个内部表 ...

  4. css3标签学习总结文章

    1. :nth-child和 :nth-of-type 区别 比如: p:nth-child(2) 满足条件:1.必须是p标签:2.必须是父元素的第2个子元素:P:nth-of-type(2) 满足条 ...

  5. DBMS_LOB包的使用

    DBMS_LOB包的使用 1.  dbms_lob.append( dest_lob  IN  OUT  NOCOPY  BLOB, src_lob  IN  BLOB) dbms_lob.appen ...

  6. jsonp总结

    由于“同源策略”的限制,ajax不能做跨域请求,jsonp是当下解决跨域请求最流行的方案,来个例子(index.html): <!doctype html> <html lang=& ...

  7. 继承,is,as,多态

    继承中的构造方法:1.创建子类对象时,一定会先创建父类对象2.如果调用的子类构造方法没有使用base,就会自动调用父类无参的构造方法,   如果父类没有无参的构造方法就会报错3.如果调用的子类构造方法 ...

  8. {{angular.js 使用技巧}} - 基于验证框架的扩展(w5cValidator)

    开场白: angular.js 是谷歌出的前端js MV*框架,我也是今年做 worktile 的时候才开始接触的,起初技术选型的时候还准备使用 backbone(毕竟很多大公司在使用他,而且也是比较 ...

  9. JS实现等比例缩放图片

    JS实现等比例缩放图片 2014-01-19 21:57 by 龙恩0707, 40 阅读, 0 评论, 收藏, 编辑 JS实现等比例缩放图片 有时候我们前端页面只有500×500像素的宽和高的布局, ...

  10. 解决Xcode升级7.0后,部分.a静态库在iOS9.0的模拟器上,link失败的问题

    简单描述一下这个问题:我们项目中使用了Google大神开发的LevelDB键值对数据库,在Xcode6,iOS8的环境下,编译好的.a静态库是可以正常使用的.但是升级后,发现在模拟器上无法link成功 ...