[转载]Asp.Net MVC 4 Web API 中的安全认证-使用OAuth – Nic Pei – 博客园.
各种语言实现的oauth认证: http://oauth.net/code/
上一篇文章介 绍了如何使用基本的http认证来实现ASP.NET web api的跨平台安全认证。 这里说明一个如何使用oauth实现的认证。oauth大家可能不陌生。那么这里需要注意的是我们使用的是.net平台一个比较好的开源oauth库。 DOTNETOPENAUTH。
就像上图所示,我们需要一个ISSSUE Server来给我们一个token,然后再去资源服务器请求资源,也就是Web API Server。
首先在oAuthIssuer服务端我们需要实现一个DotNetOpenAuth的接口:IAuthorizationServer
对接口的实现:
<span class = "kwd" > public </span><span class = "pln" > </span><span class = "kwd" > class </span><span class = "pln" > </span><span class = "typ" >OAuth2Issuer</span><span class = "pun" >:</span><span class = "pln" > </span><span class = "typ" >IAuthorizationServer</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > private </span><span class = "pln" > </span><span class = "kwd" > readonly </span><span class = "pln" > </span><span class = "typ" >IssuerConfiguration</span><span class = "pln" > _configuration</span><span class = "pun" >;</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >OAuth2Issuer</span><span class = "pun" >(</span><span class = "typ" >IssuerConfiguration</span><span class = "pln" > configuration</span><span class = "pun" >)</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > if </span><span class = "pln" > </span><span class = "pun" >(</span><span class = "pln" >configuration </span><span class = "pun" >==</span><span class = "pln" > </span><span class = "kwd" > null </span><span class = "pun" >)</span><span class = "pln" > </span><span class = "kwd" > throw </span><span class = "pln" > </span><span class = "kwd" > new </span><span class = "pln" > </span><span class = "typ" >ArgumentNullException</span><span class = "pun" >(</span><span class = "str" > "configuration" </span><span class = "pun" >);</span><span class = "pln" > _configuration </span><span class = "pun" >=</span><span class = "pln" > configuration</span><span class = "pun" >;</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >RSACryptoServiceProvider</span><span class = "pln" > </span><span class = "typ" >AccessTokenSigningKey</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > get </span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > return </span><span class = "pln" > </span><span class = "pun" >(</span><span class = "typ" >RSACryptoServiceProvider</span><span class = "pun" >)</span><span class = "pln" > _configuration</span><span class = "pun" >.</span><span class = "typ" >SigningCertificate</span><span class = "pun" >.</span><span class = "typ" >PrivateKey</span><span class = "pun" >;</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >DotNetOpenAuth</span><span class = "pun" >.</span><span class = "typ" >Messaging</span><span class = "pun" >.</span><span class = "typ" >Bindings</span><span class = "pun" >.</span><span class = "typ" >ICryptoKeyStore</span><span class = "pln" > </span><span class = "typ" >CryptoKeyStore</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > get </span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > throw </span><span class = "pln" > </span><span class = "kwd" > new </span><span class = "pln" > </span><span class = "typ" >NotImplementedException</span><span class = "pun" >();</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >TimeSpan</span><span class = "pln" > </span><span class = "typ" >GetAccessTokenLifetime</span><span class = "pun" >(</span><span class = "typ" >DotNetOpenAuth</span><span class = "pun" >.</span><span class = "typ" >OAuth2</span><span class = "pun" >.</span><span class = "typ" >Messages</span><span class = "pun" >.</span><span class = "typ" >IAccessTokenRequest</span><span class = "pln" > accessTokenRequestMessage</span><span class = "pun" >)</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > return </span><span class = "pln" > _configuration</span><span class = "pun" >.</span><span class = "typ" >TokenLifetime</span><span class = "pun" >;</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >IClientDescription</span><span class = "pln" > </span><span class = "typ" >GetClient</span><span class = "pun" >(</span><span class = "kwd" > string </span><span class = "pln" > clientIdentifier</span><span class = "pun" >)</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > const </span><span class = "pln" > </span><span class = "kwd" > string </span><span class = "pln" > secretPassword </span><span class = "pun" >=</span><span class = "pln" > </span><span class = "str" > "test1243" </span><span class = "pun" >;</span><span class = "pln" > </span><span class = "kwd" > return </span><span class = "pln" > </span><span class = "kwd" > new </span><span class = "pln" > </span><span class = "typ" >ClientDescription</span><span class = "pun" >(</span><span class = "pln" >secretPassword</span><span class = "pun" >,</span><span class = "pln" > </span><span class = "kwd" > new </span><span class = "pln" > </span><span class = "typ" >Uri</span><span class = "pun" >(</span><span class = "str" > "http://localhost/" </span><span class = "pun" >),</span><span class = "pln" > </span><span class = "typ" >ClientType</span><span class = "pun" >.</span><span class = "typ" >Confidential</span><span class = "pun" >);</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >RSACryptoServiceProvider</span><span class = "pln" > </span><span class = "typ" >GetResourceServerEncryptionKey</span><span class = "pun" >(</span><span class = "typ" >DotNetOpenAuth</span><span class = "pun" >.</span><span class = "typ" >OAuth2</span><span class = "pun" >.</span><span class = "typ" >Messages</span><span class = "pun" >.</span><span class = "typ" >IAccessTokenRequest</span><span class = "pln" > accessTokenRequestMessage</span><span class = "pun" >)</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > return </span><span class = "pln" > </span><span class = "pun" >(</span><span class = "typ" >RSACryptoServiceProvider</span><span class = "pun" >)</span><span class = "pln" > _configuration</span><span class = "pun" >.</span><span class = "typ" >EncryptionCertificate</span><span class = "pun" >.</span><span class = "typ" >PublicKey</span><span class = "pun" >.</span><span class = "typ" >Key</span><span class = "pun" >;</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "kwd" > bool </span><span class = "pln" > </span><span class = "typ" >IsAuthorizationValid</span><span class = "pun" >(</span><span class = "typ" >DotNetOpenAuth</span><span class = "pun" >.</span><span class = "typ" >OAuth2</span><span class = "pun" >.</span><span class = "typ" >ChannelElements</span><span class = "pun" >.</span><span class = "typ" >IAuthorizationDescription</span><span class = "pln" > authorization</span><span class = "pun" >)</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "com" > //claims added to the token authorization.Scope.Add("adminstrator"); </span><span class="pln"> authorization</span><span class = "pun" >.</span><span class = "typ" >Scope</span><span class = "pun" >.</span><span class = "typ" >Add</span><span class = "pun" >(</span><span class = "str" > "poweruser" </span><span class = "pun" >);</span><span class = "pln" > </span><span class = "kwd" > return </span><span class = "pln" > </span><span class = "kwd" > true </span><span class = "pun" >;</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "kwd" > bool </span><span class = "pln" > </span><span class = "typ" >IsResourceOwnerCredentialValid</span><span class = "pun" >(</span><span class = "kwd" > string </span><span class = "pln" > userName</span><span class = "pun" >,</span><span class = "pln" > </span><span class = "kwd" > string </span><span class = "pln" > password</span><span class = "pun" >)</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > return </span><span class = "pln" > </span><span class = "kwd" > true </span><span class = "pun" >;</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "kwd" > public </span><span class = "pln" > </span><span class = "typ" >DotNetOpenAuth</span><span class = "pun" >.</span><span class = "typ" >Messaging</span><span class = "pun" >.</span><span class = "typ" >Bindings</span><span class = "pun" >.</span><span class = "typ" >INonceStore</span><span class = "pln" > </span><span class = "typ" >VerificationCodeNonceStore</span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > get </span><span class = "pln" > </span><span class = "pun" >{</span><span class = "pln" > </span><span class = "kwd" > throw </span><span class = "pln" > </span><span class = "kwd" > new </span><span class = "pln" > </span><span class = "typ" >NotImplementedException</span><span class = "pun" >();</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span><span class = "pun" >}</span><span class = "pln" > </span> |
在 Web API Server端,我们需要使用Http Message Handler来获取httprequest信息;并进行是否有授权认证。
public class OAuth2Handler : DelegatingHandler { private readonly ResourceServerConfiguration _configuration; public OAuth2Handler(ResourceServerConfiguration configuration) { if (configuration == null) throw new ArgumentNullException(“configuration”); _configuration = configuration; } protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpContextBase httpContext; string userName; HashSet<string> scope; if (!request.TryGetHttpContext(out httpContext)) throw new InvalidOperationException(“HttpContext must not be null.”); var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer( (RSACryptoServiceProvider)_configuration.IssuerSigningCertificate.PublicKey.Key, (RSACryptoServiceProvider)_configuration.EncryptionVerificationCertificate.PrivateKey)); var error = resourceServer.VerifyAccess(httpContext.Request, out userName, out scope); if (error != null) return Task<HttpResponseMessage>.Factory.StartNew(error.ToHttpResponseMessage); var identity = new ClaimsIdentity(scope.Select(s => new Claim(s, s))); if (!string.IsNullOrEmpty(userName)) identity.Claims.Add(new Claim(ClaimTypes.Name, userName)); httpContext.User = ClaimsPrincipal.CreateFromIdentity(identity); Thread.CurrentPrincipal = httpContext.User; return base.SendAsync(request, cancellationToken); } }
这里的ResourceServerConfiguration 我们是使用加密证书的。
客户端调用代码:
调用API获取数据之前需要从IssueServer获取Token。
GetAccessToken:
看一下Token信息:
{“access_token”:”gAAAAIoUBVBrZ5jAxe5XeTgnJ8mGwwKsCReknueg4gLGlDQ77lR1yPfxt0yNfWLCBT7hxnHjRjuEwDTJ3J1YAnqML4MIgQg8A2cz2bs0EnxvCMfKnayKEesRM-lxLTFbWMpSxe2Xvjm61IbaXjrMkYDRMnV4Do8-7132tiOLIv02WOGlJAEAAIAAAACJ8F3SsE6cTI1XsioW_xOxHeESDzG16y01Gxm3HikYFUC3XIdekpPw0yMB4tavPmUj-kRyC1halbUX7JKf-Dihm6Ou5mexe9lcYTr9or_kH7WcDN5ZCryUK3OaecvwwjQVr5o9XD2ZyZSNDCNhVRFc5ypvP85zZCBW1KJkP3OTCV4AkMN-ROvgI8jxutYdsLLN-YbB7Ot5iypzWWbW0QxiwOzMEqG9nVtPwnIWOUMOvW5KbiELELhgjap60mwHzGrHG4TtA4jrNy8S9zjixO_q-FrgpAuC06CkSH-R4w9yPCLLDc9m3UoAnknFjd4PUbWLxCvlBpEK2sg03ENa0EOKzc2O5fEic9P-BiYt6afMwTgLkJlGBBjmCBpGZMkfLTw”,”token_type”:”bearer”,”expires_in”:”300″,”scope”:”http:\/\/localhost\/ adminstrator poweruser”}
客户端调用: