问题描述
要开始做这个简单的任务,我研究过了,我已经作为示例的跟随和复制的步骤,程序可以上传图片匿名:
私人只读客户端Id为String =我的客户ID'=> ...............
私人只读ClientSecret的String =我的客户秘密'=> ........................................
' 用法:
昏暗的URL的String = UploadImage(C:\ image.jpg文件)中:MessageBox.Show(URL)
公共职能UploadImage(BYVAL图像作为字符串)
昏暗W¯¯作为新的Web客户端()
w.Headers.Add(授权,客户ID&放大器;客户端Id)
昏暗的按键作为新System.Collections.Specialized.NameValueCollection
尝试
Keys.Add(形象,Convert.ToBase64String(File.ReadAllBytes(图片)))
昏暗responseArray为字节()= w.UploadValues(https://api.imgur.com/3/image键)
昏暗的结果= Encoding.ASCII.GetString(responseArray)
昏暗的章作为新System.Text.RegularEx pressions.Regex(链接:。(*)?,)
昏暗的比赛由于比赛= reg.Match(结果)
昏暗的URL的String = match.ToString.Replace(链接,).Replace(,).Replace(\ /,/)
返回URL
抓住参考译文异常
的MessageBox.show(出事了。&放大器; s.Message)
返回失败!
结束尝试
端功能
但我真正希望做的是上传图片到我的用户帐户,该帐户是的http:// elektrostudios .imgur.com 。
我发现this问题,但什么他回答说不清楚了我(因为我的新手知识),反正我试图使用上述功能,但只发送 BEARER
头我的 ClientSecret
ID'的原因如果我理解好什么 OAuth的2 API文档表示令牌也有可能是 ClientSecret
标识?,但我没有得到预期的结果。
所以,搜索的方式来获得适当的存取权限令牌我见过这这让我发现 RestSharp 库,并知道如何发送请求别人的问题,我做了一些修改,用它搭配Imgur API,但我得到这个错误响应:
{数据:{错误:CLIENT_ID和RESPONSE_TYPE是必需的,请求:\ / oauth2 \ /授权,法:POST },成功:假的,身份:400}
这是我有:
公用Sub GetAccessToken()
昏暗的XRC作为RestClient =新RestClient
昏暗的grant_type的String =authorization_ code
昏暗的要求作为新RestRequest(Method.POST)
昏暗strBody作为字符串
昏暗的响应,RestResponse
昏暗strResponse作为字符串
request.Method = Method.POST
request.RequestFormat = DataFormat.Xml
基本URL
xrc.BaseUrl =https://api.imgur.com
资源
request.Resource =oauth2 /授权
格式的身体
strBody =的String.Format(CLIENT_ID = {0}&放大器; RESPONSE_TYPE = {1},客户端ID,ClientSecret)
添加身体的要求
request.AddBody(授权,strBody)
'执行
响应= xrc.Execute(要求)
解析响应
strResponse = response.Content
的MessageBox.show(response.Content.ToString)
结束小组
所以我的问题是2合1:
PS:请记住,即使获得访问令牌,我不知道如何使用它后,将其存储
我试图使用@ Plutonix 解决方案,但是当我尝试要求它抛出一个异常的令牌需要一个有效的PIN第一
我使用的是有效的客户端Id和ClientSecret,我想的东西更多?这里是code:
私人imgUR作为新imgurAPI(我的客户ID,我的客户的秘密)
私人小组的button1_Click()处理Button1.Click
昏暗的世行作为新的web浏览器
imgUR.RequestPinBrowser(WB)
下面的介绍抛出一个异常:
需要一个有效的PIN第一
昏暗的结果作为imgurAPI.imgUrResults = imgUR.RequestToken
wb.Dispose()
检查结果
如果结果= imgurAPI.imgUrResults.OK然后
假设该文件存在
imgUR.UploadImage(C:\ test.jpg放在假)
Clipboard.SetText(imgUR.LastImageLink)
的MessageBox.show(imgUR.LastImageLink)
其他
的MessageBox.show(的String.Format(错误获得访问令牌状态:{0},
result.ToString))
结束如果
结束小组
这是漫长的,因为它是多了还是少了compleat API:
公共类imgurAPI 这个API的imgUR组合和服务器响应 公共枚举imgUrResults OK = 200'AKA Status200 错误我们返回 OtherAPIError = -1到目前为止,只是缺少ImgLink InvalidToken = -2 InvalidPIN = -3'销过期 InvalidRequest = -4 TokenParseError = -5 结果,我们从服务器获取 BadRequestFormat = 400'Status400 AuthorizationError = 401'Status401 故宫= 403'Status403 NOTFOUND = 404'Status404坏网址端点 RateLimitError = 429'Status429RateLimit错误 SERVERERROR = 500'Status500内部服务器错误 UknownStatus = 700'我们还没有占它(还), 可能是微不足道的或新 结束枚举 容器很酷的东西,他们给我们 朋友兵种标志 公共属性AcctUserName作为字符串 公共属性AccessToken作为字符串 公共属性RefreshToken作为字符串 公共属性届满日期时间 公共子新() AcctUserName = AccessToken = RefreshToken = 到期= DateTime.MinValue 结束小组 好友功能IsExpired()作为布尔 如果(到期> DateTime.Now)然后 返回False 其他 如果到期重置一切,让一些白痴犯规 揭露AccessToken和测试 AcctUserName = AccessToken = RefreshToken = 到期= DateTime.MinValue 返回TRUE 结束如果 端功能 末级 没有简单的男星! 与客户端ID和SecretID构造函数初始化 公共子新(CLID作为字符串,秘密作为字符串) clientID的= CLID clientSecret =秘密 myPin = imgToken =新令牌 LastImageLink = UseClipboard = TRUE AnonOnly = FALSE 结束小组 与客户端ID和SecretID构造函数初始化 公共子新(CLID作为字符串) clientID的= CLID clientSecret = myPin = imgToken =新令牌 LastImageLink = UseClipboard = TRUE AnonOnly = TRUE 结束小组 私人clientID的作为字符串 私人clientSecret作为字符串 私人AnonOnly由于布尔= TRUE 令牌不公开 私人imgToken令牌 公共属性LastImageLink作为字符串 公共属性UseClipboard由于布尔 'precise时刻到期时为code使用 公共只读属性TokenExpiry为DATETIME 得到 如果imgToken状态并没有任何然后 返回imgToken.Expiry 其他 返回任何结果 结束如果 最终获取 高端物业 公共功能GetExpiryCountdown()作为字符串 返回的String.Format({0:HH \:毫米\:SS},GetExpiryTimeRemaining) 端功能 剩下的时间作为时间跨度 公共功能GetExpiryTimeRemaining()由于时间跨度 昏暗的TS作为新的时间跨度(0) 如果imgToken是没有那么 返回TS 结束如果 如果DateTime.Now> imgToken.Expiry然后 返回TS 其他 TS = imgToken.Expiry - DateTime.Now 返回TS 结束如果 端功能 公共功能IsTokenValid()作为布尔 如果imgToken是没有那么 返回False 结束如果 如果String.IsNullOrEmpty(imgToken.AcctUserName)然后 返回False 结束如果 如果imgToken.IsExpired然后 返回False 结束如果 返回TRUE 端功能 目前,该密码是从调用应用程序设置。也许有可能 饲料在日志中imgUr得到一个PIN 私人myPin作为字符串 公众只写属性脚作为字符串 设置(值作为字符串) myPin =价值 结束设定 高端物业 导航到网页。 看到wb_DocumentCompleted为code到 从文档解析PIN 公用Sub RequestPinBrowser(BrowserCtl作为web浏览器) 如果AnonOnly然后 你不需要输入PIN佚名 抛出新ApplicationException的(A PIN是不是需要ANON上传) 退出小组 结束如果 如果BrowserCtl是没有那么 抛出新的ArgumentException(缺少有效的web浏览器参考) 退出小组 结束如果 imgur API格式 https://api.imgur.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=REQUESTED_RESPONSE_TYPE&state=APPLICATION_STATE 昏暗的OAuthUrlTemplate =https://api.imgur.com/oauth2/authorize?client_id={0}&response_type={1}&state={2} 昏暗ReqURL作为字符串=的String.Format(OAuthUrlTemplate,客户端ID,针,齐格) BrowserCtl.Url =新的URI(ReqURL) 结束小组 公共功能GetAccessToken()作为imgUrResults 有不同类型的令牌请求 这只能通过提交的数据变化 昏暗的SREQ的String =的String.Format(CLIENT_ID = {0}&放大器; client_secret = {1}&安培; grant_type =引脚和放大器;针= {2}, 客户端ID,clientSecret,myPin) 如果myPin =的String.Empty然后 返回imgUrResults.InvalidPIN 结束如果 如果AnonOnly然后返回imgUrResults.InvalidRequest 呼叫通用令牌处理器 返回RequestToken(SREQ) 端功能 请求令牌 专用功能RequestToken(sRequest作为字符串)作为imgUrResults 昏暗的URL的String =https://api.imgur.com/oauth2/token/ 昏暗myResult中作为imgUrResults = imgUrResults.OK 使用POST方法创建请求的URL, 昏暗的要求作为的WebRequest = WebRequest.Create(URL) request.Method =POST 转换的要求,设置内容格式,长度 昏暗的数据字节()= System.Text.Encoding.UTF8.GetBytes(sRequest) request.ContentType =应用/的X WWW的形式urlen codeD request.ContentLength = data.Length 写上日期,请求流 昏暗DSTREAM作为物流= request.GetRequestStream dstream.Write(数据,0,data.Length) dstream.Close() '上使用的反应和潜在WebException JSON 昏暗的JSON作为新JavaScriptSerializer() 'prepare一个响应 昏暗的响应,WebResponse类=无 昏暗SvrResponses作为词典(字符串,对象) 尝试 响应= request.GetResponse 转换状态code到纲领性结果 myResult中= GetResultFromStatus(CTYPE(响应,HttpWebResponse).STATUS code) 抓住EX作为WebException 一个坏/使用引脚将抛出一个异常 昏暗的RESP的String =新的StreamReader(ex.Response.GetResponseStream())。ReadToEnd() SvrResponses = CTYPE(json.DeserializeObject(resp.ToString) 词典(字符串,对象)) myResult中= GetResultFromStatus(Convert.ToString(SvrResponses(状态))) 结束尝试 Console.WriteLine(CTYPE(响应,HttpWebResponse).StatusDescription) Console.WriteLine(CTYPE(响应,HttpWebResponse).STATUS code) 'premature疏散 如果myResult中<> imgUrResults.OK然后 如果DSTREAM状态并没有任何然后 dstream.Close() dstream.Dispose() 结束如果 如果响应状态并没有任何然后 response.Close() 结束如果 返回myResult中 结束如果 读响应流 DSTREAM = response.GetResponseStream 昏暗SvrResponseStr作为字符串 使用SR作为StreamReader的=新的StreamReader(DSTREAM) 流串 SvrResponseStr = sr.ReadToEnd Console.WriteLine(SvrResponse) 结束使用 靠近流 dstream.Close() dstream.Dispose() response.Close() 尝试 使用JSON serialier来解析结果(S) 转换SvrRsponse到词典 SvrResponses = CTYPE(json.DeserializeObject(SvrResponseStr) 词典(字符串,对象)) 从字典'得到的东西 imgToken.AccessToken = Convert.ToString(SvrResponses(access_token)) imgToken.RefreshToken = Convert.ToString(SvrResponses(refresh_token)) imgToken.AcctUserName = Convert.ToString(SvrResponses(account_username)) 转换expires_in到某个时间点 昏暗nExp作为整数= Convert.ToInt32(Convert.ToString(SvrResponses(expires_in))) imgToken.Expiry = Date.Now.Add(新时间跨度(0,0,nExp)) 针是一次性使用 把它扔掉,因为它不再有效 myPin = 抓住EX为例外 的MessageBox.show(ex.Message) myResult中= imgUrResults.TokenParseError 结束尝试 返回myResult中 端功能 公共接口尝试上传前检查PARAMS 公共功能UploadImage(文件名作为字符串,可选佚名由于布尔= FALSE)作为imgUrResults 如果AnonOnly然后 返回DoImageUpLoad(文件名,AnonOnly) 其他 如果IsTokenValid()= false,那么 返回imgUrResults.InvalidToken 结束如果 结束如果 应该是调用的应用程序来测试FileExist的工作 返回DoImageUpLoad(文件名,佚名) 端功能 实际的文件上传 专用功能DoImageUpLoad(文件名作为字符串,可选佚名由于布尔= FALSE)作为imgUrResults 昏暗的结果作为imgUrResults = imgUrResults.OK LastImageLink = 尝试 创建一个Web客户端 使用wc =新Net.WebClient() 读图像 昏暗的值=新的NameValueCollection()从 { {形象,Convert.ToBase64String(File.ReadAllBytes(文件名))} } 报头的类型取决于这是否是一个匿名或帐户上传 如果匿名然后 wc.Headers.Add(授权,客户ID+ clientID的) 其他 wc.Headers.Add(授权,承载及放大器; imgToken.AccessToken) 结束如果 '上传,得到响应 昏暗的响应= wc.UploadValues(https://api.imgur.com/3/upload.xml,值) 读响应转换成字节数组流 使用SR作为新的StreamReader(新的MemoryStream(响应)) 昏暗uplStatus作为字符串 昏暗SvrResponse作为字符串= sr.ReadToEnd XDOC暗淡作为的XDocument = XDocument.Parse(SvrResponse) 获得请求的状态 uplStatus = xdoc.Root.Attribute(状态)。值 结果= GetResultFromStatus(uplStatus) 如果结果= imgUrResults.OK然后 LastImageLink = xdoc.Descendants(链接)。值 只覆盖服务器结果状态 如果String.IsNullOrEmpty(LastImageLink)然后 避免NRE别处 LastImageLink = 我们做错了什么事解析结果 但是这一次是一种轻微 结果= imgUrResults.OtherAPIError 结束如果 结束如果 结束使用 如果UseClipboard AndAlso(结果= imgUrResults.OK)然后 Clipboard.SetText(LastImageLink) 结束如果 结束使用 抓住EX为例外 昏暗ERRMSG作为字符串= ex.Message 限速 如果ex.Message.Contains(429)然后 结果= imgUrResults.RateLimitError ' 内部错误 elseif的ex.Message.Contains(500)然后 结果= imgUrResults.ServerError 结束如果 结束尝试 返回结果 端功能 专用功能GetResultFromStatus(状态作为字符串)作为imgUrResults 选择案例status.Trim 案200 返回imgUrResults.OK 案400 返回imgUrResults.BadRequestFormat 案401 返回imgUrResults.AuthorizationError 案403 返回imgUrResults.Forbidden 案404 返回imgUrResults.NotFound 案429 返回imgUrResults.RateLimitError 案500 返回imgUrResults.ServerError 案例否则 不要 - 制定出其他收益 返回imgUrResults.UknownStatus 最终选择 端功能 专用功能GetResultFromStatus(地位的Int32)作为imgUrResults 有些地方,我们得到一个字符串,其他整数 返回GetResultFromStatus(status.ToString) 端功能末级
如何使用它
该过程需要一个网络浏览器的用户导航并请求PIN码。为了测试/开发,我用了一个WebBrowser控件和陷入僵局从返回页面中的PIN码。
注:用于测试,我的imgUR帐户被设置为桌面,因为我们正在从一个桌面应用程序发送。此外,这是给你的图像发送到您的帐户。没有办法给别人上传到你的账户没有给你的秘密ID和/或嵌入你的主人ImgUR登录名和密码的应用程序。这是怎么ImgUR设计了它。
一个。创建imgUR对象:
朋友imgUR作为imgurAPI
imgUR =新imgurAPI(小于你的客户端ID>,<您的秘密code基)
乙。得到一个针 - 方法一
通过应用程序的WebBrowser控件
imgUR.RequestPinBrowser(WB)
这将带你到一个imgur页面,您必须授权密码的问题上传到您的帐户。输入您的账户名,密码,点击允许。与PIN一个新的页面会显示出来。从网页复制的PIN码进行一些其他的控制,可以把它交给了imgurAPI类。
有低于code解析密码页面,并把它变成另一种控制。
方法二
- 使用自己的外部浏览器转到
https://api.imgur.com/oauth2/authorize? CLIENT_ID = YOUR_CLIENT_ID和放大器; RESPONSE_TYPE =引脚和放大器;状态=齐格
- 登录
- 复制您会收到成
文本框
什么的PIN将其发送到imgurAPI: - 设置PIN:
imgUR.Pin =<< PIN码接收的GT;>
这个过程是相同的无论哪种方式,你是否想拥有包括在您的形式WebBrowser控件只是一个问题。 PIN码是唯一的好很短的时间,所以你必须使用它来获得访问令牌的时候了。
℃。获得访问令牌
'imgUrResults是由类暴露枚举
昏暗的结果作为imgurAPI.imgUrResults = imgUR.RequestToken
注:
- 的imgUR类将保持该标记
- 在当前令牌在1小时内到期(3600秒)
D:上传文件
上传使用 imgUR.UploadImage(文件名,boolAnon)
文件名 - 文件上传
boolAnon - 布尔标志。假=上传此文件到您的帐户相较于匿名通用池方法。
例如:
'获得令牌
昏暗的结果作为imgurAPI.imgUrResults = imgUR.RequestToken
检查结果
如果结果= imgurAPI.imgUrResults.OK然后
假设该文件存在
imgUR.UploadImage(C:\ TEMP \ London.jpg,FALSE)
其他
的MessageBox.show(的String.Format(错误获得访问令牌状态:{0},
result.ToString))
结束如果
的文件上传后,程序查找在响应中的链接。如果链接可以分析,这将是可从 LastImageLink
属性并粘贴到剪贴板为好。
其它属性,设置和方法
LastImageLink (字符串) - 上传的最后一幅图像的URL
UseClipBoard (布尔) - 如果为true,imgurAPI类职位上传的图片的链接到剪贴板
TokenExpiry (日期) - 即当前令牌到期日期时间
GetTokenTimeRemaining ()由于时间跨度 - 一个时间跨度再presenting多久当前令牌到期前
公共功能GetTokenCountdown()作为String - 格式化TimeRemaining串
公开只写属性脚作为String - 要获得访问令牌需要的PIN
公共功能IsTokenValid()作为布尔 - 当前令牌有效
公共功能IsTokenExpired ()作为布尔 - TimeRemaining简单的布尔版VS DateTime.Now
备注
- 在令牌可续签或延长。但由于他们持续了一个小时,这似乎很多。
- 引脚只有良好的时间很短。一旦密码被交换信物的imgurAPI(本级)清除PIN。如果有问题,得到令牌,你必须首先获得一个新的PIN(或粘贴最后一个,如果你只是得到它几分钟前)。
- 上传的图片是不可见的世界的,除非/直到你改变你的帐户设置。
- 您可以重置SecretID(设置 - >应用程序)。如果你这样做,你还需要重置它使用这个API类的应用程序,并重新编译(或从一个配置文件中读取)。
如果您使用的是 web浏览器
控制得到一个密码,你可以添加这个code到 DocumentCompleted
事件刮从HTML的PIN:
的WB是控制
昏暗HTMLDOC作为System.Windows.Forms.HtmlDocument = wb.Document
昏暗ELP作为System.Windows.Forms.HtmlElement = htmlDoc.GetElementById(针)
如果ELP状态并没有任何然后
SPIN = elP.GetAttribute(价值)
如果String.IsNullOrEmpty(SPIN)= false,那么
用户必须按下按钮`imgUR.Pin = tbPIN.Text`
'这样的情况下是在HTML变化时,用户可以覆盖
并输入正确的PIN
Me.tbPIN.Text = SPIN
结束如果
结束如果
关于OAuth的型号
这是非官方的 - 从阅读的文档,并与API的信息了解到。适用于imgur API V3因为这个日期。的
有什么自动得到一个PIN。这种或那种方式,你必须导航到一个URL在浏览器中,输入您的帐户名和密码来获得一个PIN。这是设计让你自己,个人的授权一些外部应用程序来访问您的帐户的内容。
方法一上面使用.NET WebBrowser控件来做到这一点。通过这种方法,我们可以肯定的是你和imgur类两者都使用相同的端点/ URL,因为它通过浏览器控件发送你。
方法二只是你在某些浏览器去那里,任何浏览器。登录,获取密码,并将其粘贴到imgurAPI类。
无论方法,正确的端点/ URL中使用的是:
<一个href="https://api.imgur.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=pin&state=foobar" rel="nofollow">https://api.imgur.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=pin&state=foobar
使用使用imgurAPI类的窗体上的浏览器,我们显然我们可以肯定的是,你和类两者都使用相同的URL和客户端ID。在$ C $下的DocumentComplete
获取PIN码到文本框的仅您还需要设置它的类:
myimgUR.PIN = tbPin code.Text
引脚是一次性使用的,而过期。
所以开发尤其是当你停止code,加一些东西然后重新运行自然,code将不再有旧令牌或PIN。如果最后一个PIN码是最近和的没有的提交,你可能没有得到一个新的,但我发现这是很难记住,如果是这样的话。
类把引脚作为一次性使用。一旦令牌已收到,它清除出去,因为他们一直在使用,不再有效的变量。
最后修改
- 添加了一个匿名只有模式
要使用类上传仅在匿名模式(一般的网站,而不是您的帐户),该SecretID是不需要的。为此,使用新的构造函数重载:
的Public Sub New(clientID的作为字符串)
该设置为只工作一个匿名类和一定的方法将返回错误或使用基于账户的方法,如为gettoken
当阵痛异常。如果你只是客户端ID初始化它,它仍然在 AnonOnly 模式之前,必须重新与该客户端ID和SecretID两者的对象。
有没有真正的理由使用它作为AnonOnly(除非你没有一个帐户),因为UploadImage方法允许你通过文件来指定它作为一个匿名上传:
功能UploadImage(文件名作为字符串,
可选的匿名由于布尔= FALSE)作为imgUrResults
- 在修订/澄清了imgUrResults枚举
这就是要包罗万象:一些回报指示由类检测到问题,其他都是这只是传承下去服务器响应
。- 删除
IsTokenExpired
IsTokenValid
更彻底。还有其他的方法来获取剩余时间或实际到期。
- 新增各类错误捕获/处理
- 要求输入PIN时,检查是否有有效的WebBrowser控件
- 精制用于获取服务器状态code中的方法将图像上传后
- 重新编排了一些处理给了优先收益类远程服务器的状态
To start doing this "simple" task I've researched for a procedure that I've taken as an example here to follow and reproduce the steps, the procedure can upload an image "anonymously":
Private ReadOnly ClientId As String = "My Client ID" ' => "..............."
Private ReadOnly ClientSecret As String = "My Client Secret" ' => "........................................"
' Usage:
' Dim url As String = UploadImage("C:\Image.jpg") : MessageBox.Show(url)
Public Function UploadImage(ByVal image As String)
Dim w As New WebClient()
w.Headers.Add("Authorization", "Client-ID " & ClientId)
Dim Keys As New System.Collections.Specialized.NameValueCollection
Try
Keys.Add("image", Convert.ToBase64String(File.ReadAllBytes(image)))
Dim responseArray As Byte() = w.UploadValues("https://api.imgur.com/3/image", Keys)
Dim result = Encoding.ASCII.GetString(responseArray)
Dim reg As New System.Text.RegularExpressions.Regex("link"":""(.*?)""")
Dim match As Match = reg.Match(result)
Dim url As String = match.ToString.Replace("link"":""", "").Replace("""", "").Replace("\/", "/")
Return url
Catch s As Exception
MessageBox.Show("Something went wrong. " & s.Message)
Return "Failed!"
End Try
End Function
But what I really would like to do is upload the image into my user account, which is http://elektrostudios.imgur.com.
I've found this question but what him said in the answer is not clear for my (due to my newbie knowledges), anyways I've tried to use the function above but just sending the BEARER
header with my ClientSecret
ID 'cause If I understood good what the oauth 2 api documentation says the token could also be the ClientSecret
Id?, but I don't get the expected result.
So searching the way to get a proper acces token I've seen this else question which helped me to discover RestSharp library and to know how to send the request, I did some modifications to use it with Imgur API but I'm getting this error-response:
{"data":{"error":"client_id and response_type are required","request":"\/oauth2\/authorize","method":"POST"},"success":false,"status":400}
This is what I have:
Public Sub GetAccessToken()
Dim xrc As RestClient = New RestClient
Dim grant_type As String = "authorization_code"
Dim request As New RestRequest(Method.POST)
Dim strBody As String
Dim response As RestResponse
Dim strResponse As String
request.Method = Method.POST
request.RequestFormat = DataFormat.Xml
'Base URL
xrc.BaseUrl = "https://api.imgur.com"
'Resource
request.Resource = "oauth2/authorize"
'Format body
strBody = String.Format("client_id={0}&response_type={1}", ClientId, ClientSecret)
'Add body to request
request.AddBody("Authorization", strBody)
'Execute
response = xrc.Execute(request)
'Parse Response
strResponse = response.Content
MessageBox.Show(response.Content.ToString)
End Sub
So my question are 2 in 1:
PS: Please remember that even getting the access token I don't know how to use it after stored it.
I'm trying to use @Plutonix solution but when I try to request the Token it throws an exception "Need a valid PIN first
", I'm using a valid ClientId and ClientSecret, I'm missing something more?, here is the code:
Private imgUR As New imgurAPI("my client id", "my client secret")
Private Sub Button1_Click() Handles Button1.Click
Dim wb As New WebBrowser
imgUR.RequestPinBrowser(wb)
' The instruction below throws an exception:
' "Need a valid PIN first"
Dim result As imgurAPI.imgUrResults = imgUR.RequestToken
wb.Dispose()
' check result
If result = imgurAPI.imgUrResults.OK Then
' assumes the file exists
imgUR.UploadImage("C:\Test.jpg", False)
Clipboard.SetText(imgUR.LastImageLink)
MessageBox.Show(imgUR.LastImageLink)
Else
MessageBox.Show(String.Format("Error getting access token. Status:{0}",
result.ToString))
End If
End Sub
This is long, because it is more or less a compleat API:
Public Class imgurAPI
' combination of this API and imgUR server responses
Public Enum imgUrResults
OK = 200 ' AKA Status200
' errors WE return
OtherAPIError = -1 ' so far, just missing ImgLink
InvalidToken = -2
InvalidPIN = -3 ' pins expire
InvalidRequest = -4
TokenParseError = -5
' results we get from server
BadRequestFormat = 400 ' Status400
AuthorizationError = 401 ' Status401
Forbidden = 403 ' Status403
NotFound = 404 ' Status404 ' bad URL Endpoint
RateLimitError = 429 ' Status429 ' RateLimit Error
ServerError = 500 ' Status500 ' internal server error
UknownStatus = 700 ' We havent accounted for it (yet),
' may be trivial or new
End Enum
' container for the cool stuff they send us
Friend Class Token
Public Property AcctUserName As String
Public Property AccessToken As String
Public Property RefreshToken As String
Public Property Expiry As DateTime
Public Sub New()
AcctUserName = ""
AccessToken = ""
RefreshToken = ""
Expiry = DateTime.MinValue
End Sub
Friend Function IsExpired() As Boolean
If (Expiry > DateTime.Now) Then
Return False
Else
' if expired reset everything so some moron doesnt
' expose AccessToken and test for ""
AcctUserName = ""
AccessToken = ""
RefreshToken = ""
Expiry = DateTime.MinValue
Return True
End If
End Function
End Class
' NO simple ctor!!!
' constructor initialized with ClientID and SecretID
Public Sub New(clID As String, secret As String)
clientID = clID
clientSecret = secret
myPin = ""
imgToken = New Token
LastImageLink = ""
UseClipboard = True
AnonOnly = False
End Sub
' constructor initialized with ClientID and SecretID
Public Sub New(clID As String)
clientID = clID
clientSecret = ""
myPin = ""
imgToken = New Token
LastImageLink = ""
UseClipboard = True
AnonOnly = True
End Sub
Private clientID As String
Private clientSecret As String
Private AnonOnly As Boolean = True
' tokens are not public
Private imgToken As Token
Public Property LastImageLink As String
Public Property UseClipboard As Boolean
' precise moment when it expires for use in code
Public ReadOnly Property TokenExpiry As DateTime
Get
If imgToken IsNot Nothing Then
Return imgToken.Expiry
Else
Return Nothing
End If
End Get
End Property
Public Function GetExpiryCountdown() As String
Return String.Format("{0:hh\:mm\:ss}", GetExpiryTimeRemaining)
End Function
' time left as a TimeSpan
Public Function GetExpiryTimeRemaining() As TimeSpan
Dim ts As New TimeSpan(0)
If imgToken Is Nothing Then
Return ts
End If
If DateTime.Now > imgToken.Expiry Then
Return ts
Else
ts = imgToken.Expiry - DateTime.Now
Return ts
End If
End Function
Public Function IsTokenValid() As Boolean
If imgToken Is Nothing Then
Return False
End If
If String.IsNullOrEmpty(imgToken.AcctUserName) Then
Return False
End If
If imgToken.IsExpired Then
Return False
End If
Return True
End Function
' Currently, the PIN is set from a calling App. Might be possible
' to feed the log in to imgUr to get a PIN
Private myPin As String
Public WriteOnly Property Pin As String
Set(value As String)
myPin = value
End Set
End Property
' Navigates to the web page.
' see wb_DocumentCompleted for code to
' parse the PIN from the document
Public Sub RequestPinBrowser(BrowserCtl As WebBrowser)
If AnonOnly Then
' you do not need a PIN for Anon
Throw New ApplicationException("A PIN is not needed for ANON Uploads")
Exit Sub
End If
If BrowserCtl Is Nothing Then
Throw New ArgumentException("Missing a valid WebBrowser reference")
Exit Sub
End If
' imgur API format
' https://api.imgur.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=REQUESTED_RESPONSE_TYPE&state=APPLICATION_STATE
Dim OAuthUrlTemplate = "https://api.imgur.com/oauth2/authorize?client_id={0}&response_type={1}&state={2}"
Dim ReqURL As String = String.Format(OAuthUrlTemplate, clientID, "pin", "ziggy")
BrowserCtl.Url = New Uri(ReqURL)
End Sub
Public Function GetAccessToken() As imgUrResults
' there are different types of token requests
' which vary only by the data submitted
Dim sReq As String = String.Format("client_id={0}&client_secret={1}&grant_type=pin&pin={2}",
clientID, clientSecret, myPin)
If myPin = String.Empty Then
Return imgUrResults.InvalidPIN
End If
If AnonOnly Then Return imgUrResults.InvalidRequest
' call generic token processor
Return RequestToken(sReq)
End Function
' request a Token
Private Function RequestToken(sRequest As String) As imgUrResults
Dim url As String = "https://api.imgur.com/oauth2/token/"
Dim myResult As imgUrResults = imgUrResults.OK
' create request for the URL, using POST method
Dim request As WebRequest = WebRequest.Create(url)
request.Method = "POST"
' convert the request, set content format, length
Dim data As Byte() = System.Text.Encoding.UTF8.GetBytes(sRequest)
request.ContentType = "application/x-www-form-urlencoded"
request.ContentLength = data.Length
' write the date to request stream
Dim dstream As Stream = request.GetRequestStream
dstream.Write(data, 0, data.Length)
dstream.Close()
' json used on the response and potential WebException
Dim json As New JavaScriptSerializer()
' prepare for a response
Dim response As WebResponse = Nothing
Dim SvrResponses As Dictionary(Of String, Object)
Try
response = request.GetResponse
' convert status code to programmatic result
myResult = GetResultFromStatus(CType(response, HttpWebResponse).StatusCode)
Catch ex As WebException
' a bad/used pin will throw an exception
Dim resp As String = New StreamReader(ex.Response.GetResponseStream()).ReadToEnd()
SvrResponses = CType(json.DeserializeObject(resp.ToString),
Dictionary(Of String, Object))
myResult = GetResultFromStatus(Convert.ToString(SvrResponses("status")))
End Try
'Console.WriteLine(CType(response, HttpWebResponse).StatusDescription)
'Console.WriteLine(CType(response, HttpWebResponse).StatusCode)
' premature evacuation
If myResult <> imgUrResults.OK Then
If dstream IsNot Nothing Then
dstream.Close()
dstream.Dispose()
End If
If response IsNot Nothing Then
response.Close()
End If
Return myResult
End If
' read the response stream
dstream = response.GetResponseStream
Dim SvrResponseStr As String
Using sr As StreamReader = New StreamReader(dstream)
' stream to string
SvrResponseStr = sr.ReadToEnd
'Console.WriteLine(SvrResponse)
End Using
' close streams
dstream.Close()
dstream.Dispose()
response.Close()
Try
' use json serialier to parse the result(s)
' convert SvrRsponse to Dictionary
SvrResponses = CType(json.DeserializeObject(SvrResponseStr),
Dictionary(Of String, Object))
' get stuff from Dictionary
imgToken.AccessToken = Convert.ToString(SvrResponses("access_token"))
imgToken.RefreshToken = Convert.ToString(SvrResponses("refresh_token"))
imgToken.AcctUserName = Convert.ToString(SvrResponses("account_username"))
' convert expires_in to a point in time
Dim nExp As Integer = Convert.ToInt32(Convert.ToString(SvrResponses("expires_in")))
imgToken.Expiry = Date.Now.Add(New TimeSpan(0, 0, nExp))
' Pins are single use
' throw it away since it is no longer valid
myPin = ""
Catch ex As Exception
'MessageBox.Show(ex.Message)
myResult = imgUrResults.TokenParseError
End Try
Return myResult
End Function
' public interface to check params before trying to upload
Public Function UploadImage(filename As String, Optional Anon As Boolean = False) As imgUrResults
If AnonOnly Then
Return DoImageUpLoad(filename, AnonOnly)
Else
If IsTokenValid() = False Then
Return imgUrResults.InvalidToken
End If
End If
' should be the job of the calling app to test for FileExist
Return DoImageUpLoad(filename, Anon)
End Function
' actual file uploader
Private Function DoImageUpLoad(fileName As String, Optional Anon As Boolean = False) As imgUrResults
Dim result As imgUrResults = imgUrResults.OK
LastImageLink = ""
Try
' create a WebClient
Using wc = New Net.WebClient()
' read image
Dim values = New NameValueCollection() From
{
{"image", Convert.ToBase64String(File.ReadAllBytes(fileName))}
}
' type of headers depends on whether this is an ANON or ACCOUNT upload
If Anon Then
wc.Headers.Add("Authorization", "Client-ID " + clientID)
Else
wc.Headers.Add("Authorization", "Bearer " & imgToken.AccessToken)
End If
' upload, get response
Dim response = wc.UploadValues("https://api.imgur.com/3/upload.xml", values)
' read response converting byte array to stream
Using sr As New StreamReader(New MemoryStream(response))
Dim uplStatus As String
Dim SvrResponse As String = sr.ReadToEnd
Dim xdoc As XDocument = XDocument.Parse(SvrResponse)
' get the status of the request
uplStatus = xdoc.Root.Attribute("status").Value
result = GetResultFromStatus(uplStatus)
If result = imgUrResults.OK Then
LastImageLink = xdoc.Descendants("link").Value
' only overwrite the server result status
If String.IsNullOrEmpty(LastImageLink) Then
' avoid NRE elsewhere
LastImageLink = ""
' we did something wrong parsing the result
' but this one is kind of minor
result = imgUrResults.OtherAPIError
End If
End If
End Using
If UseClipboard AndAlso (result = imgUrResults.OK) Then
Clipboard.SetText(LastImageLink)
End If
End Using
Catch ex As Exception
Dim errMsg As String = ex.Message
' rate limit
If ex.Message.Contains("429") Then
result = imgUrResults.RateLimitError
' internal error
ElseIf ex.Message.Contains("500") Then
result = imgUrResults.ServerError
End If
End Try
Return result
End Function
Private Function GetResultFromStatus(status As String) As imgUrResults
Select Case status.Trim
Case "200"
Return imgUrResults.OK
Case "400"
Return imgUrResults.BadRequestFormat
Case "401"
Return imgUrResults.AuthorizationError
Case "403"
Return imgUrResults.Forbidden
Case "404"
Return imgUrResults.NotFound
Case "429"
Return imgUrResults.RateLimitError
Case "500"
Return imgUrResults.ServerError
Case Else
' Stop - work out other returns
Return imgUrResults.UknownStatus
End Select
End Function
Private Function GetResultFromStatus(status As Int32) As imgUrResults
' some places we get a string, others an integer
Return GetResultFromStatus(status.ToString)
End Function
End Class
HOW TO USE IT
The process requires a web browser for the user to navigate and request a PIN. For testing/development, I used a WebBrowser control and snagged the PIN from the returned page.
Note: for testing, my imgUR account was setup as DESKTOP, since we are sending from a DESKTOP app. Also, this is for YOU sending images to YOUR account. There is not a way for OTHERS to upload to YOUR account without giving out your secret ID and/or embedding your master ImgUR Login and password in the App. That is how ImgUR designed it.
A. Create an imgUR object:
Friend imgUR As imgurAPI
imgUR = New imgurAPI(<your Client ID>,<your secret code>)
B. Get a Pin - Method One
' pass the app's WebBrowser Control
imgUR.RequestPinBrowser(wb)
This will take you to a imgur page where you must authorize the issue of a PIN for uploading to your account. Enter your Account Name, Password, Click ALLOW. A new page with the PIN will be displayed. Copy the PIN from the webpage to some other control which can feed it to the imgurAPI Class.
There is code below to parse the PIN page and get it into another control.
Method Two
- Using your own external browser, go to
https://api.imgur.com/oauth2/authorize? client_id=YOUR_CLIENT_ID&response_type=pin&state=ziggy
- Log In
- Copy the PIN you receive into a
TextBox
or something to send it to the imgurAPI: - Set pin:
imgUR.Pin = <<PIN YOU RECEIVED>>
The process is the same either way, just a matter of whether you want to have to include a WebBrowser control in your form. PINs are only good for a short time, so you must use it to get an access token right away.
C. Get Access token
' imgUrResults is an enum exposed by the class
Dim result As imgurAPI.imgUrResults = imgUR.RequestToken
Notes:
- the imgUR class will retain the token
- tokens currently expire in 1 hour (3600 seconds)
D: Upload a File
Upload using imgUR.UploadImage(filename, boolAnon)
Filename - the file to upload
boolAnon - Boolean flag. False = upload this file to your account vs the Anon general pool method.
Example:
' get token
Dim result As imgurAPI.imgUrResults = imgUR.RequestToken
' check result
If result = imgurAPI.imgUrResults.OK Then
' assumes the file exists
imgUR.UploadImage("C:\Temp\London.jpg", False)
Else
MessageBox.Show(String.Format("Error getting access token. Status:{0}",
result.ToString))
End If
After the file uploads, the procedure looks for the link in the response. If the link can be parsed, it will be available from the LastImageLink
property and pasted to the ClipBoard as well.
Misc Properties, Settings and Methods
LastImageLink (String) - URL of the last image uploaded
UseClipBoard (Bool) - When true, imgurAPI class posts the link to the uploaded image to the Clipboard
TokenExpiry (Date) - The DateTime that the current token expires
GetTokenTimeRemaining() As TimeSpan - A TimeSpan representing how long before the current token expires
Public Function GetTokenCountdown() As String - Formatted string of TimeRemaining
Public WriteOnly Property Pin As String - the PIN required to get an access token
Public Function IsTokenValid() As Boolean - is the current token valid
Public Function IsTokenExpired() As Boolean - simple Boolean version of TimeRemaining vs DateTime.Now
Notes
- Tokens can be renewed or extended. But since they last for an hour, this seems plenty.
- PINS are only good for a short time. Once a PIN is exchanged for a token the imgurAPI (this class) clears the PIN. If there is a problem getting the Token, you will have to get a new PIN first (or paste the last one if you just got it a few minutes ago).
- Uploaded images are not visible to the world at large unless/until you change the setting on your account.
- You can reset your SecretID (Settings -> Applications). If you do, you will need to also reset it for apps using this API class, and recompile (or read it from a config file).
If you use a WebBrowser
control to get a PIN, you can add this code to the DocumentCompleted
event to scrape the PIN from the HTML:
' wb is the control
Dim htmlDoc As System.Windows.Forms.HtmlDocument = wb.Document
Dim elP As System.Windows.Forms.HtmlElement = htmlDoc.GetElementById("pin")
If elP IsNot Nothing Then
sPin = elP.GetAttribute("value")
If String.IsNullOrEmpty(sPin) = False Then
' user has to push the button for `imgUR.Pin = tbPIN.Text`
' this is in case the HTML changes, the user can override
' and input the correct PIN
Me.tbPIN.Text = sPin
End If
End If
About the OAuth Model
this is unofficial - info learned from reading the docs and working with the API. Applies to imgur API v3 as of this date.
There is nothing automated about getting a PIN. One way or another you must navigate to a URL in a browser and enter your account name and Password to get a PIN. This is by design so that you, yourself, personally are authorizing some external app to access your account content.
Method One above uses a .NET WebBrowser control to do this. With this method we can be sure that both you and the imgur class are using the same Endpoint/URL because it sends you there via the browser control.
Method Two is just you go there in some browser, any browser. Log in, get a PIN, and paste it to the imgurAPI class.
No matter the method, the correct Endpoint/URL to use is:
https://api.imgur.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=pin&state=foobar
Using a browser on the form using the imgurAPI class, we obviously we can be sure that both you and the class are using the same URL and ClientID. The code for DocumentComplete
fetches the PIN into the TextBox only you still need to set it in the class:
myimgUR.PIN = tbPinCode.Text
PINS are single use, and expire.
So when developing especially, and you stop the code, add some stuff then rerun naturally, the code will no longer have the old Token or PIN. If the last PIN was recent and not submitted, you might not have to get a new one, but I find it is hard to remember if that is the case.
The class treats PINS as single use. Once a Token has been received, it clears out the variable since they have been used and are no longer valid.
Final Edit
- Added an Anon Only mode
To use the class to upload ONLY in Anon mode (to the general site, not your account), the SecretID is not needed. For this, use the new constructor overload:
Public Sub New(clientID As String)
This sets the class to work an Anon ONLY and certain methods will return an error or throe an exception when using Account based methods such as GetToken
. If you initialize it with just ClientID, it remains in AnonOnly mode until you recreate the object with the both the ClientID and SecretID.
There is no real reason to use it as AnonOnly (unless you do not have an account) since the UploadImage method allows you to specify it as an Anon upload by file:
Function UploadImage(filename As String,
Optional Anon As Boolean = False) As imgUrResults
- Revised/clarified the imgUrResults Enum
This is meant to be all-encompassing: some returns indicate a problem detected by the class, others are server responses which are simply passed along.
- Removed
IsTokenExpired
IsTokenValid
is more thorough. There are other methods to get the time remaining or the actual Expiry.
- Added assorted error trapping/handling
- Check for a valid WebBrowser control when requesting a PIN
- Refined the method used to get the server status code after an image is uploaded
- Reworked some handling to give prioritize remote server status over class returns
.
这篇关于访问直通OAuth的imgUr(上传到用户帐户)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!