http://stackoverflow.com/questions/12499602/body-joints-angle-using-kinect?rq=1
新浪微博跟update相关的api已经挂了很多天了一直没有恢复正常,返回错误:40070 Error limited application access api!,新浪开放平台的论坛里n多的人都在等这个恢复,新浪官方也相当的恶心出问题了连个公告都没有,既不说什么原因又不说什么时候能恢复,。还是有版主说是api正在升级礼拜1恢复正常今天都礼拜2了还是不行。基于这个原因我的android版的新浪微博客户端已经停工好几天了,刚好是跟update相关的一些功能。
客户端开发不成了,就自己做做服务端程序,提供类似新浪微博rest api服务, api其实说简单也很简单了,无法是通过链接对外提供json或者xml格式的数据和接收外部提供的数据进去相应的存储、删除、更新等操作。过程中碰到的最麻烦的问题就是OAuth认证功能了,在做android版的新浪微博客户端时候也花了蛮长的时间对OAuth认证进行研究,在客户端原先是采用了oauth-signpost开源项目,后来由于某些原因就放弃了这个开源类库,自己重新写了OAuth认证部分的实现, 现在做服务端的OAuth认证,其实有过做客户端的经验做服务端也差不多,简单的说无非是客户端对参数字符串进行签名然后把签名值传输到服务端,服务端也对同样对参数字符串进行签名,把从客户端传过来的签名值进去比较,简单的说就这么个过程,具体实现肯定比这个要复杂多了,不明真相的同学可以google一下OAuth进行深入的学习研究了。
服务端程序用asp.net和C#编写了而非java,理由很简单本人对.net更加熟悉。由于想快速的实现效果采用了oauth-dot-net开源项目并没有全部自己写。
一、首先新建名为Rest Api的ASP.NET Web应用程序,然后添加 oauth-dot-net开源项目相关的几个dll(Castle.Core.dll、Castle.MicroKernel.dll、Castle.Windsor.dll、CommonServiceLocator.WindsorAdapter.dll、Microsoft.Practices.ServiceLocation.dll、OAuth.Net.Common.dll、OAuth.Net.Components.dll、OAuth.Net.ServiceProvider.dll)。
二、在Web.config文件里添加相应的配置,具体可以参考OAuth.Net.Examples.EchoServiceProvider项目,然后在Global.asax.cs添加如下代码:
public
override
void
Init()
{
IServiceLocator injector
=
new
WindsorServiceLocator(
new
WindsorContainer(
new
XmlInterpreter(
new
ConfigResource(
"
oauth.net.components
"
))));
ServiceLocator.SetLocatorProvider(()
=>
injector);
}
接下来是比较重要,就是request_token、authorize、access_token的实现,OAuth认证实现的几个过程,不理解可以看android开发我的新浪微博客户端-OAuth篇(2.1) ,具体代码实现很多是参考OAuth.Net.Examples.EchoServiceProvider示例项目。
三、 首先新建ConsumerStore.cs类,用来存储Consumer信息,由于测试项目所以存储在内存中并没有考虑保存到数据库,真实项目的时候请把相应的Consumer信息保存到数据库中。Consumer信息对应新浪微博其实就是应用的App Key和App Secret,当开发者在新浪微博建一个新的应用获取App Key和App Secret,所以完整的应该还需要一个开发一个提供给第三方开发者申请获取App Key和App Secret的功能页面,这里就不具体实现,直接在代码里写死了一个名为测试应用的Consumer,App Key:2433927322,App Secret:87f042c9e8183cbde0f005a00db1529f,这个提供给客户端测试用。 具体代码如下:
public
sealed
class
ConsumerStore : InMemoryConsumerStore, IConsumerStore
{
internal
static
readonly
IConsumer FixedConsumer
=
new
OAuthConsumer(
"
2433927322
"
,
"
87f042c9e8183cbde0f005a00db1529f
"
,
"
测试应用
"
, ConsumerStatus.Valid);
public
ConsumerStore()
{
this
.ConsumerDictionary.Add(
ConsumerStore.FixedConsumer.Key,
ConsumerStore.FixedConsumer);
}
public
override
bool
Add(IConsumer consumer)
{
throw
new
NotSupportedException(
"
Consumers cannot be added to this store--it is fixed.
"
);
}
public
override
bool
Contains(
string
consumerKey)
{
return
ConsumerStore.FixedConsumer.Key.Equals(consumerKey);
}
public
override
bool
Update(IConsumer consumer)
{
throw
new
NotSupportedException(
"
Consumers cannot be updated in this store--it is fixed.
"
);
}
public
override
bool
Remove(IConsumer consumer)
{
throw
new
NotSupportedException(
"
Consumers cannot be removed from this store--it is fixed.
"
);
}
}
四、接下来就是request_token功能,新建RequestTokenHandler.cs ,这个是OAuth.Net.ServiceProvider.RequestTokenHandler子类,并且是httpHandlers所以需要在Web.config中添加httpHandlers配置,这个用来接收客户端程序的请求,返回给客户端程序Request Token和Request Secret用,具体代码如下:
public
sealed
class
RequestTokenHandler : OAuth.Net.ServiceProvider.RequestTokenHandler
{
protected
override
void
IssueRequestToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
//
产生RequestToken
IRequestToken token
=
this
.GenerateRequestToken(httpContext, requestContext);
requestContext.RequestToken
=
token;
Uri callbackUri;
if
(Uri.TryCreate(requestContext.Parameters.Callback, UriKind.Absolute,
out
callbackUri))
{
if
(
!
ServiceProviderContext.CallbackStore.ContainsCallback(token))
{
//
保存Callback地址了
ServiceProviderContext.CallbackStore.AddCallback(token, callbackUri);
}
}
else
OAuthRequestException.ThrowParametersRejected(
new
string
[] { Constants.CallbackParameter },
"
Not a valid Uri.
"
);
//
把token.Token和token.Secret输出到客户端,
requestContext.ResponseParameters[Constants.TokenParameter]
=
token.Token;
requestContext.ResponseParameters[Constants.TokenSecretParameter]
=
token.Secret;
}
protected
override
IRequestToken GenerateRequestToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
return
ServiceProviderContext.TokenGenerator.CreateRequestToken(requestContext.Consumer, requestContext.Parameters);
}
}
五、 接着是authorize功能,新建名为authorize.aspx的页面,用来给用户输入账号和密码进行授权的页面,这个页面很简单具体如下图,在这个页面中获取用户输入的账户和密码跟数据库中存储的用户账号和密码进行验证,如果验证通过返回之前客户端提供的callback地址,并且给这个地址添加一个校验码,具体代码如下:
public
partial
class
authorize : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
}
protected
void
Button1_Click(
object
sender, EventArgs e)
{
if
(loginName.Text
==
"
test
"
&&
password.Text
==
"
123
"
)
{
string
toke
=
Request.Params[
"
oauth_token
"
];
IRequestToken tk
=
ServiceProviderContext.TokenStore.GetRequestToken(toke);
Uri callback
=
ServiceProviderContext.CallbackStore.GetCalback(tk);
string
oauth_verifier
=
ServiceProviderContext.VerificationProvider.Generate(tk);
Response.Redirect(callback.ToString()
+
"
?oauth_verifier=
"
+
oauth_verifier);
}
}
}
六、接下来就是access_token功能,新建AccessTokenHandler.cs , 这个是OAuth.Net.ServiceProvider.AccessTokenHandler子类,并且是httpHandlers所以需要在Web.config中添加httpHandlers配置,这个用来接收客户端程序的请求,返回给客户端程序Access Token和Access Secret用,具体代码如下:
public
sealed
class
AccessTokenHandler : OAuth.Net.ServiceProvider.AccessTokenHandler
{
protected
override
void
IssueAccessToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
//
产生access token
IAccessToken accessToken
=
this
.GenerateAccessToken(httpContext, requestContext);
accessToken.Status
=
TokenStatus.Authorized;
//
把accessToken和accessSecret输出到客户端,
requestContext.ResponseParameters[Constants.TokenParameter]
=
accessToken.Token;
requestContext.ResponseParameters[Constants.TokenSecretParameter]
=
accessToken.Secret;
}
protected
override
IAccessToken GenerateAccessToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
return
ServiceProviderContext.TokenGenerator.CreateAccessToken(requestContext.Consumer, requestContext.RequestToken);
}
}
public
class
TokenGenerator : ITokenGenerator
{
internal
static
readonly
IRequestToken FixedRequestToken
=
new
OAuthRequestToken(
"
requestkey
"
,
"
requestsecret
"
,
ConsumerStore.FixedConsumer,
TokenStatus.Authorized,
null
,
ServiceProviderContext.DummyIdentity,
new
string
[] { });
internal
static
readonly
IAccessToken FixedAccessToken
=
new
OAuthAccessToken(
"
accesskey
"
,
"
accesssecret
"
,
ConsumerStore.FixedConsumer,
TokenStatus.Authorized,
TokenGenerator.FixedRequestToken);
public
IRequestToken CreateRequestToken(IConsumer consumer, OAuthParameters parameters)
{
return
TokenGenerator.FixedRequestToken;
}
public
IAccessToken CreateAccessToken(IConsumer consumer, IRequestToken requestToken)
{
return
TokenGenerator.FixedAccessToken;
}
}
public
class
TokenStore : InMemoryTokenStore, ITokenStore
{
public
TokenStore()
{
this
.RequestTokenDictionary.Add(
TokenGenerator.FixedRequestToken.Token,
TokenGenerator.FixedRequestToken);
this
.AccessTokenDictionary.Add(
TokenGenerator.FixedAccessToken.Token,
TokenGenerator.FixedAccessToken);
}
public
override
bool
Add(IRequestToken token)
{
throw
new
NotSupportedException(
"
Tokens cannot be added to the token store--it is fixed.
"
);
}
public
override
bool
Add(IAccessToken token)
{
throw
new
NotSupportedException(
"
Tokens cannot be added to the token store--it is fixed.
"
);
}
public
override
bool
Update(IRequestToken token)
{
throw
new
NotSupportedException(
"
Tokens cannot be updated in the token store--it is fixed.
"
);
}
public
override
bool
Update(IAccessToken token)
{
throw
new
NotSupportedException(
"
Tokens cannot be updated in the token store--it is fixed.
"
);
}
public
override
bool
Remove(IRequestToken token)
{
throw
new
NotSupportedException(
"
Tokens cannot be removed from the token store--it is fixed.
"
);
}
public
override
bool
Remove(IAccessToken token)
{
throw
new
NotSupportedException(
"
Tokens cannot be removed from the token store--it is fixed.
"
);
}
}
这样就完成了一个最最简单小型的服务端OAuth认证,然后用android客户端进行测试ok通过。
注意点:
一、android模拟器访问本地服务地址为10.0.2.2,比如http://localhost:3423/authorize.aspx在模拟器中用http://10.0.2.2:3423/authorize.aspx。
二、OAuth.Net类库的OAuth.Net.Common项目中的interface ICallbackStore 添加了一个Uri GetCalback(IRequestToken token);并且在具体的实现类InMemoryCallbackStore添加了实习代码:
public Uri GetCalback(IRequestToken token)
{
lock (this.callbackStore)
{
if (this.callbackStore.ContainsKey(token))
{
return this.callbackStore[token];
}
else
{
return null;
}
}
}
三、为了能用我前面做的给新浪用的android客户端,对于类库源代码AccessTokenHandler的ParseParameters方法做了如下修改,因为新浪请求api的时候都会加一个source的参数:
protected virtual void ParseParameters(HttpContext httpContext, OAuthRequestContext requestContext)
{
.......
parameters.AllowOnly(
Constants.ConsumerKeyParameter,
Constants.TokenParameter,
Constants.SignatureMethodParameter,
Constants.SignatureParameter,
Constants.TimestampParameter,
Constants.NonceParameter,
Constants.VerifierParameter,
Constants.VersionParameter, // (optional)
Constants.RealmParameter, // (optional)
"source");
......
}