前段时间随意抽离了一部分代码作为OAuth2的示例代码,若干处会造成困扰,现说明如下:
1publicclassOAuthController : Controller2{3PRivatestaticstring_authorizeUrl = ConfigurationManager.AppSettings["AuthorizeUrl"];4privatestaticstring[] _queryParameters =newstring[] {"client_id","redirect_uri","state","response_type","scope"};5privatereadonlyAuthorizationServer _authorizationServer =newAuthorizationServer(newOAuth2AuthorizationServer());67[AcceptVerbs(HttpVerbs.Get)]8publicActionResult Authorize(stringuserkey)9{10varpendingRequest =this._authorizationServer.ReadAuthorizationRequest(Request);11if(pendingRequest ==null)12{13thrownewHttpException((int)HttpStatusCode.BadRequest,"Missing authorization request.");14}1516if(string.IsNullOrEmpty(userkey))17{18stringurl = _authorizeUrl, callback =Request.Url.GetLeftPart(Uripartial.Path);19StringBuilder querystring =newStringBuilder(string.Format("client_id={0}&", HttpUtility.UrlEncode(this.Request.QueryString["client_id"]))), callbackQuery =newStringBuilder();20foreach(stringkeyinthis.Request.QueryString.Keys)21{22if(!_queryParameters.Contains(key))23querystring.Append(string.Format("{0}={1}&", key, HttpUtility.UrlEncode(this.Request.QueryString[key])));24else25callbackQuery.Append(string.Format("{0}={1}&", key, HttpUtility.UrlEncode(this.Request.QueryString[key])));26}27if(callbackQuery.Length >0)28{29callback += ("?"+ callbackQuery.ToString().TrimEnd('&'));30querystring.Append(string.Format("callback={0}&", HttpUtility.UrlEncode(callback)));31}32if(querystring.Length >0)33{34url += ("?"+ querystring.ToString().TrimEnd('&'));35}36returnRedirect(url);37}38else39{40using(vardb =newOAuthDbContext())41{42varclient = db.Clients.FirstOrDefault(o => o.ClientIdentifier ==pendingRequest.ClientIdentifier);43if(client ==null)44thrownewAuthorizeException("40143","不受信任的商户");45else46{47varuser =DESCrypt.Decrypt(userkey, client.ClientSecret);48varapproval =this._authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, user);49varresponse =this._authorizationServer.Channel.PrepareResponse(approval);50returnresponse.AsActionResult();51}52}53}54}5556publicActionResult Index()57{58ViewBag.Body ="Welcome To OAuth2.0";59returnView();60}61}
这是授权服务端的主要代码。AuthorizeUrl和userkey分别表示什么意思?
这里涉及到我所在公司的具体情况,简单地说,用户授权的具体逻辑是由另外单独的站点(AuthorizeUrl表示,为方便描述,称为A站点)引导,所以这里的代码主要起到一个跳转的作用。我们看DotNetOpenAuth的官方Demo,会发现授权服务端有登录页面、授权页面等等,其实本质是一样的,只是拆分成两个站点。除了OAuth参数,此处可能会传递其它参数,所以使用_queryParameters来区分,并分别构建两部分查询字符串,OAuth参数会附加到callback地址参数上,用户授权后会从A站点跳回该地址(此处就是该action所表示的地址),然后返回浏览器授权码。
关于userkey,大家看到有个解密的步骤(第47行),so,这肯定是考虑到安全问题。公司的业务逻辑大多采用userid标示用户,为自增长int类型,用户通过A站点授权后通过浏览器callback时,userid可以在地址栏中被捕捉到,假如复制该地址并随意更改userid值,就很有可能在对应用户未授权的情况下获得其访问权限。所以我们不允许直接传递userid,而是经过一层对称加密,这就是userkey的由来。如果授权逻辑并未拆分成独立站点,那么就不存在这种情况了。
后续我可能会再补充若干内容,由于工作较忙,只对有朋友提出疑问的地方做一说明;若有其它问题,请告知,我会不定期更新。