2012-06-13 30 views
12

Tôi đang bối rối về những gì tôi đang làm sai ở đây ...ASP Classic amazon s3 phép nghỉ ngơi

<script language="javascript" runat="server"> 
    function GMTNow(){return new Date().toGMTString()} 
</script> 
<% 

Const AWS_BUCKETNAME = "uk-bucketname" 
Const AWS_ACCESSKEY = "GOES HERE" 
Const AWS_SECRETKEY = "SECRET" 
LocalFile = Server.Mappath("/test.jpg") 

Dim sRemoteFilePath 
    sRemoteFilePath = "/files/test.jpg" 'Remote Path, note that AWS paths (in fact they aren't real paths) are strictly case sensitive 

Dim strNow 
    strNow = GMTNow() ' GMT Date String 

Dim StringToSign 
    StringToSign = Replace("PUT\n\nimage/jpeg\n\nx-amz-date:" & strNow & "\n/"& AWS_BUCKETNAME & sRemoteFilePath, "\n", vbLf) 

Dim Signature 
    Signature = BytesToBase64(HMACSHA1(AWS_SECRETKEY, StringToSign)) 

Dim Authorization 
    Authorization = "AWS " & AWS_ACCESSKEY & ":" & Signature 

Dim AWSBucketUrl 
    AWSBucketUrl = "http://s3.amazonaws.com/" & AWS_BUCKETNAME 

With Server.CreateObject("Microsoft.XMLHTTP") 
    .open "PUT", AWSBucketUrl & sRemoteFilePath, False 
    .setRequestHeader "Authorization", Authorization 
    .setRequestHeader "Content-Type", "image/jpeg" 
    .setRequestHeader "Host", AWS_BUCKETNAME & ".s3.amazonaws.com" 
    .setRequestHeader "x-amz-date", strNow 
    .send GetBytes(LocalFile) 'Get bytes of local file and send 
    If .status = 200 Then ' successful 
     Response.Write "<a href="& AWSBucketUrl & sRemoteFilePath &" target=_blank>Uploaded File</a>" 
    Else ' an error ocurred, consider xml string of error details 
     Response.ContentType = "text/xml" 
     Response.Write .responseText 
    End If 
End With 

Function GetBytes(sPath) 
    dim fs,f 
set fs=Server.CreateObject("Scripting.FileSystemObject") 
set f=fs.GetFile(sPath) 
GetBytes = f.Size 
set f=nothing 
set fs=nothing 
End Function 

Function BytesToBase64(varBytes) 
    With Server.CreateObject("MSXML2.DomDocument").CreateElement("b64") 
     .dataType = "bin.base64" 
     .nodeTypedValue = varBytes 
     BytesToBase64 = .Text 
    End With 
End Function 

Function HMACSHA1(varKey, varValue) 
    With Server.CreateObject("System.Security.Cryptography.HMACSHA1") 
     .Key = UTF8Bytes(varKey) 
     HMACSHA1 = .ComputeHash_2(UTF8Bytes(varValue)) 
    End With 
End Function 

Function UTF8Bytes(varStr) 
    With Server.CreateObject("System.Text.UTF8Encoding") 
     UTF8Bytes = .GetBytes_4(varStr) 
    End With 
End Function 
%> 

Bây giờ nhận được lỗi.

msxml3.dll error '800c0008' 

The download of the specified resource has failed. 

/s3.asp, line 39 
+0

Bạn có tìm cách giải quyết vấn đề của mình không Chris? – TheCarver

+0

Không vẫn không: ( –

+0

Xin chào Chris, bạn đã đăng ký dịch vụ Amazon S3 cũng như tài khoản AWS chưa? Xem chủ đề này https://forums.aws.amazon.com/thread.jspa?threadID=45582 –

Trả lời

2

Chữ ký Amazon phải được mã hóa url theo cách hơi khác với những gì VBSCript mã hóa. Các chức năng sau đây sẽ mã hóa các kết quả một cách chính xác:

JScript Version:

function amazonEncode(s) 
{ 
    return Server.UrlEncode(s).replace(/\+/g,"%20").replace(/\%2E/g,".").replace(/\%2D/g,"-").replace(/\%7E/g,"~").replace(/\%5F/g,"_"); 
} 

VBScript Version:

function amazonEncode(s) 
    dim retval 
    retval = Server.UrlEncode(s) 
    retval = replace(retval,"+","%20") 
    retval = replace(retval,"%2E",".") 
    retval = replace(retval,"%2D","-") 
    retval = replace(retval,"%7E","~") 
    retval = replace(retval,"%5F","_") 
    amazonEncode = retval 
end function 

Đối với base64, tôi sử dụng .NET ấy đã xây dựng chức năng cho nó. Tôi đã phải tạo một DLL để bọc nó, để tôi có thể sử dụng nó từ JScript (hoặc VBScript).

Dưới đây là làm thế nào để tạo ra rằng dll:

Download the free C# 2010 Express and install it. 
You also need to use two other tools that you won’t have a path to, so you will need to add the path to your PATH environment variable, so at a cmd prompt search for regasm.exe, guidgen.exe and sn.exe (you might find several versions – select the one with the latest date). 
• cd\ 
• dir/s regasm.exe 
• dir/s sn.exe 
• dir/s guidgen.exe 


So as an example, a COM object that has just one method which just returns “Hello”: 
Our eventual aim is to use it like this: 
<%@Language=JScript%> 
<% 
var x = Server.CreateObject("blah.whatever"); 
Response.Write(x.someMethod()); 
%> 

or 

<%@Language=VBScript%> 
<% 
dim x 
set x = Server.CreateObject("blah.whatever") 
Response.Write x.someMethod() 
%> 

• Start C# and create a new project 
• Select “Empty Project” 
• Give it a name – this becomes the namespace by default (the blah in the sample above) 
• Next save the project (so you know where to go for the next bit). This will create a folder structure like so: 
o blah this contains your solution files that the editor needs (blah.sln etc) 
 blah this contains your source code and project files 
• bin 
o Debug   the compiled output ends up here 
• Next, using the cmd console, navigate to the root blah folder and create a key pair file: 
    sn –k key.snk 
• Next you need a unique guid (enter guidgen at the cmd prompt) 
o Select registry format 
o Click “New Guid” 
o Click “Copy” 
• Back to C# editor – from the menu, select Project – Add Class 
• Give it a name – this is the whatever in the sample above 
• After the opening brace just after the namespace line type: 
    [GuidAttribute(“paste your guid here”)] 
    remove the curly brackets from your pasted guid 
• You will need to add another “using” at the top 
    using System.Runtime.InteropServices; 
• Finally you need to create someMethod 

The final C# code looks like this (the bits in red may be different in your version): 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace blah 
{ 
    [GuidAttribute("AEF4F27F-9E97-4189-9AD5-64386A1699A7")] 
    public class whatever 
    { 
     public string someMethod() 
     { 
      return "Hello"; 
     } 
    } 
} 

• Next, from the menu, select Project – Properties 
o On the left, select Application and, for the Output type dropdown, select “Class Library” 
o On the left, select Signing and tick the “Sign the assembly” box, then browse to the key.snk file you made earlier 
o Save the properties (CTRL-S) 
• Next build the dll (Press F6) – This will create a dll in the Debug folder 
• Open a cmd window as administrator (right click cmd.exe and select “Run as Administrator”) 
• Navigate to the Debug folder and enter the following to register the assembly: 
    regasm blah.dll /tlb:blah.tlb /codebase blah 

That’s it – the above is a genuine COM component and will work in other applications, the example below allows for event handling and only really works in ASP due to the default property mechanism of ASP: 

Mã cho những thứ base64 sẽ là:

// returns a base 64 encoded string that has been encrypted with SHA256 
    // parameters: 
    // s string to encrypt 
    // k key to use during encryption 
    public string getBase64SHA256(string s, string k) 
    { 
     HMACSHA256 sha = new HMACSHA256(); 
     System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 
     sha.Key = encoding.GetBytes(k); 
     byte[] hashBytes = sha.ComputeHash(encoding.GetBytes(s)); 
     return System.Convert.ToBase64String(hashBytes); 
    } 

    // returns a base 64 encoded string that has been encrypted with SHA1 
    // parameters: 
    // s string to encrypt 
    // k key to use during encryption 
    public string getBase64SHA1(string s, string k) 
    { 
     HMACSHA1 sha = new HMACSHA1(); 
     System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 
     sha.Key = encoding.GetBytes(k); 
     byte[] hashBytes = sha.ComputeHash(encoding.GetBytes(s)); 
     return System.Convert.ToBase64String(hashBytes); 
    } 

Bạn sẽ cần các usings liên quan:

using System.Security.Cryptography; 

Chữ ký đầy đủ phải có tất cả các cặp tên-giá trị chuỗi truy vấn theo thứ tự bảng chữ cái trước khi tính toán SHA và base64. Đây là phiên bản của tôi về chức năng tạo chữ ký:

function buildAmazonSignature(host,req,qstring) 
{ 
    var str="", i, arr = String(qstring).split("&"); 

    for (i=0; i<arr.length; i++) 
     arr[i] = arr[i].split("="); 
    arr.sort(amazonSortFunc); 

    for (i=0; i<arr.length; i++) 
    { 
     if (str != "") 
      str += "&"; 

     str += arr[i][0] + "=" + arr[i][1]; 
    } 

    str = "GET\n"+host+"\n"+req+"\n"+str; 

    var utils = Server.CreateObject("FMAG.Utils"); 
    var b64 = utils.getBase64SHA256(str, "xxxxxxxxxx"); 
    utils = null; 

    return amazonEncode(b64); 
} 

function amazonSortFunc(a,b) 
{ 
    return (a[0]<b[0])?-1:((a[0]>b[0])?1:0); 
} 

VBScript không có một cơ sở sắp xếp mảng rất tốt, vì vậy bạn sẽ phải làm việc một trong ra ngoài chính mình - xin lỗi

Ngoài ra tôi có dấu thời gian ở định dạng này:

YYYY-MM-DDThh: mm: SSZ

Ngoài ra những thứ trong chuỗi truy vấn bao gồm những điều sau đây:

AWSAccessKeyId 
SignatureMethod 
SignatureVersion 
Version 
Expires 
Action 

Hy vọng rằng sẽ giúp

9

Tôi muốn giải thích cách S3 Rest Api hoạt động như xa như tôi biết.
Đầu tiên, bạn cần tìm hiểu chuỗi ký tự để Amazon chấp nhận.

Format:

StringToSign = HTTP-Verb + "\n" + 
    Content-MD5 + "\n" + 
    Content-Type + "\n" + 
    Date + "\n" + 
    CanonicalizedAmzHeaders + 
    CanonicalizedResource; 

Tạo ký chuỗi:

Signature = Base64(HMAC-SHA1(YourSecretAccessKeyID, UTF-8-Encoding-Of(StringToSign))); 

Đi qua uỷ quyền tiêu đề:

Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; 

Thật không may bạn sẽ chơi byte để byte vì không có bất kỳ SDK phát hành cho asp cổ điển. Vì vậy, phải hiểu bằng cách đọc toàn bộ tranghttp://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html

Đối với chuỗi ký như bạn có thể thấy ở trên định dạng, có ba tiêu đề gốc được API bảo lưu. Loại nội dung, Nội dung-MD5Ngày. Các tiêu đề này phải tồn tại trong chuỗi ký, ngay cả yêu cầu của bạn không phải là chúng trống mà không có tên tiêu đề, chỉ là giá trị của nó. Có một ngoại lệ, tiêu đề Date phải trống trong chuỗi để ký nếu tiêu đề x-amz-date đã tồn tại trong yêu cầu. Sau đó, nếu yêu cầu có tiêu đề amazon chuẩn, bạn nên thêm chúng làm cặp khóa-giá trị như x-amz-headername:value. Tuy nhiên, có một ngoại lệ khác cần được xem xét cho nhiều tiêu đề. Nhiều tiêu đề phải kết hợp với một tiêu đề có các giá trị được phân cách bằng dấu phẩy.

Đúng

x-AMZ-headername: value1, value2

sai

x-AMZ-headername: value1 \ n
x -amz-tên người dùng: value2

Quan trọng nhất là, tiêu đề phải là thứ tự tăng dần theo nhóm trong chuỗi ký. Đầu tiên, tiêu đề được đặt trước với thứ tự tăng dần, sau đó tiêu đề chuẩn với thứ tự tăng dần.

Tôi khuyên bạn nên sử dụng chức năng DomDocument để tạo chuỗi được mã hóa Base64. Ngoài ra thay vì thành phần Windows Scripting (tệp .wsc), bạn có thể sử dụng các lần kết nối của .Net chẳng hạn như System.Security.Cryptography để tạo băm có khóa hiệu quả hơn với công suất System.Text. Tất cả các khả năng tương tác này có sẵn trong các máy chủ web IIS ngày nay.
Vì vậy, như một ví dụ tôi đã viết kịch bản bên dưới, chỉ cần gửi tệp tới nhóm bạn đã chỉ định. Xem xét và kiểm tra nó.
Tên tệp cục bộ được giả định là myimage.jpg và sẽ được tải lên có cùng tên với thư mục gốc của nhóm.

<script language="javascript" runat="server"> 
function GMTNow(){return new Date().toGMTString()} 
</script> 
<% 
Const AWS_BUCKETNAME = "uk-bucketname" 
Const AWS_ACCESSKEY = "GOES HERE" 
Const AWS_SECRETKEY = "SECRET" 

LocalFile = Server.Mappath("/test.jpg") 

Dim sRemoteFilePath 
    sRemoteFilePath = "/files/test.jpg" 'Remote Path, note that AWS paths (in fact they aren't real paths) are strictly case sensitive 

Dim strNow 
    strNow = GMTNow() ' GMT Date String 

Dim StringToSign 
    StringToSign = Replace("PUT\n\nimage/jpeg\n\nx-amz-date:" & strNow & "\n/"& AWS_BUCKETNAME & sRemoteFilePath, "\n", vbLf) 

Dim Signature 
    Signature = BytesToBase64(HMACSHA1(AWS_SECRETKEY, StringToSign)) 

Dim Authorization 
    Authorization = "AWS " & AWS_ACCESSKEY & ":" & Signature 

Dim AWSBucketUrl 
    AWSBucketUrl = "https://" & AWS_BUCKETNAME & ".s3.amazonaws.com" 

With Server.CreateObject("MSXML2.ServerXMLHTTP.6.0") 
    .open "PUT", AWSBucketUrl & sRemoteFilePath, False 
    .setRequestHeader "Authorization", Authorization 
    .setRequestHeader "Content-Type", "image/jpeg" 
    .setRequestHeader "Host", AWS_BUCKETNAME & ".s3.amazonaws.com" 
    .setRequestHeader "x-amz-date", strNow 
    .send GetBytes(LocalFile) 'Get bytes of local file and send 
    If .status = 200 Then ' successful 
     Response.Write "<a href="& AWSBucketUrl & sRemoteFilePath &" target=_blank>Uploaded File</a>" 
    Else ' an error ocurred, consider xml string of error details 
     Response.ContentType = "text/xml" 
     Response.Write .responseText 
    End If 
End With 

Function GetBytes(sPath) 
    With Server.CreateObject("Adodb.Stream") 
     .Type = 1 ' adTypeBinary 
     .Open 
     .LoadFromFile sPath 
     .Position = 0 
     GetBytes = .Read 
     .Close 
    End With 
End Function 

Function BytesToBase64(varBytes) 
    With Server.CreateObject("MSXML2.DomDocument").CreateElement("b64") 
     .dataType = "bin.base64" 
     .nodeTypedValue = varBytes 
     BytesToBase64 = .Text 
    End With 
End Function 

Function HMACSHA1(varKey, varValue) 
    With Server.CreateObject("System.Security.Cryptography.HMACSHA1") 
     .Key = UTF8Bytes(varKey) 
     HMACSHA1 = .ComputeHash_2(UTF8Bytes(varValue)) 
    End With 
End Function 

Function UTF8Bytes(varStr) 
    With Server.CreateObject("System.Text.UTF8Encoding") 
     UTF8Bytes = .GetBytes_4(varStr) 
    End With 
End Function 
%> 


+0

Tôi nhận được lỗi "lỗi msxml6.dll '80072f7c' Yêu cầu chuyển hướng HTTP không thành công" bất kỳ ý tưởng nào có thể gây ra lỗi này? –

+0

@ChrisDowdeswell Bạn đã thực hiện những thay đổi nào trong mã ngoại trừ tên nhóm, khóa truy cập và khóa bí mật? –

+0

Không có gì ngoại trừ các biến bạn đặt ... :( –

0

Cảm ơn bạn rất nhiều cho câu hỏi này, nó đã được một giúp đỡ rất nhiều ví dụ để bắt đầu WSH tôi/VBScript cho dịch vụ sao lưu S3 của tôi ;-)

Tôi không có nhiều thời gian, vì vậy tôi sẽ không xem chi tiết những thứ tôi đã thay đổi từ mã của Chris, nhưng xin vui lòng tìm bên dưới số kịch bản nguyên mẫu của chúng tôi hoạt động hoàn hảo ;-)

Đây chỉ là WSH/VBScript, vì vậy bạn không cần IIS để chạy nó, bạn chỉ cần dán nội dung vào một tệp bằng " .vbs" mở rộng, và bạn có thể sau đó trực tiếp thực hiện nó ;-)

Option Explicit 
'-- Amazon Web Services > My Account > Access Credentials > Access Keys --' 
Dim strAccessKeyID: strAccessKeyID = "..." 
Dim strSecretAccessKey: strSecretAccessKey = "..." 
'-- Parameters: --' 
Dim strLocalFile: strLocalFile = "..." 
Dim strRemoteFile: strRemoteFile = "..." 
Dim strBucket: strBucket = "..." 
'-- Authentication: --' 
Dim strNowInGMT: strNowInGMT = NowInGMT() 
Dim strStringToSign: strStringToSign = _ 
    "PUT" & vbLf & _ 
    "" & vbLf & _ 
    "text/xml" & vbLf & _ 
    strNowInGMT & vbLf & _ 
    "/" & strBucket + "/" & strRemoteFile 
Dim strSignature: strSignature = ConvertBytesToBase64(HMACSHA1(strSecretAccessKey, strStringToSign)) 
Dim strAuthorization: strAuthorization = "AWS " & strAccessKeyID & ":" & strSignature 
'-- Upload: --' 
Dim xhttp: Set xhttp = CreateObject("MSXML2.ServerXMLHTTP") 
xhttp.open "PUT", "http://" & strBucket & ".s3.amazonaws.com/" & strRemoteFile, False 
xhttp.setRequestHeader "Content-Type", "text/xml" 
xhttp.setRequestHeader "Date", strNowInGMT 'Yes, this line is mandatory ;-) --' 
xhttp.setRequestHeader "Authorization", strAuthorization 
xhttp.send GetBytesFromFile(strLocalFile) 
If xhttp.status = "200" Then 
    WScript.Echo "The file has been successfully uploaded ;-)" 
Else 
    WScript.Echo "There was an error :-(" & vbCrLf & vbCrLf & _ 
    xhttp.responseText 
End If 
Set xhttp = Nothing 
'-- NowInGMT ------------------------------------------------------------------' 
Function NowInGMT() 
    'This is probably not the best implementation, but it works ;-) --' 
    Dim sh: Set sh = WScript.CreateObject("WScript.Shell") 
    Dim iOffset: iOffset = sh.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias") 
    Dim dtNowGMT: dtNowGMT = DateAdd("n", iOffset, Now()) 
    Dim strDay: strDay = "NA" 
    Select Case Weekday(dtNowGMT) 
    Case 1 strDay = "Sun" 
    Case 2 strDay = "Mon" 
    Case 3 strDay = "Tue" 
    Case 4 strDay = "Wed" 
    Case 5 strDay = "Thu" 
    Case 6 strDay = "Fri" 
    Case 7 strDay = "Sat" 
    Case Else strDay = "Error" 
    End Select 
    Dim strMonth: strMonth = "NA" 
    Select Case Month(dtNowGMT) 
    Case 1 strMonth = "Jan" 
    Case 2 strMonth = "Feb" 
    Case 3 strMonth = "Mar" 
    Case 4 strMonth = "Apr" 
    Case 5 strMonth = "May" 
    Case 6 strMonth = "Jun" 
    Case 7 strMonth = "Jul" 
    Case 8 strMonth = "Aug" 
    Case 9 strMonth = "Sep" 
    Case 10 strMonth = "Oct" 
    Case 11 strMonth = "Nov" 
    Case 12 strMonth = "Dec" 
    Case Else strMonth = "Error" 
    End Select 
    Dim strHour: strHour = CStr(Hour(dtNowGMT)) 
    If Len(strHour) = 1 Then strHour = "0" & strHour End If 
    Dim strMinute: strMinute = CStr(Minute(dtNowGMT)) 
    If Len(strMinute) = 1 Then strMinute = "0" & strMinute End If 
    Dim strSecond: strSecond = CStr(Second(dtNowGMT)) 
    If Len(strSecond) = 1 Then strSecond = "0" & strSecond End If 
    Dim strNowInGMT: strNowInGMT = _ 
    strDay & _ 
    ", " & _ 
    Day(dtNowGMT) & _ 
    " " & _ 
    strMonth & _ 
    " " & _ 
    Year(dtNowGMT) & _ 
    " " & _ 
    strHour & _ 
    ":" & _ 
    strMinute & _ 
    ":" & _ 
    strSecond & _ 
    " +0000" 
    NowInGMT = strNowInGMT 
End Function 
'-- GetBytesFromString --------------------------------------------------------' 
Function GetBytesFromString(strValue) 
    Dim stm: Set stm = CreateObject("ADODB.Stream") 
    stm.Open 
    stm.Type = 2 
    stm.Charset = "ascii" 
    stm.WriteText strValue 
    stm.Position = 0 
    stm.Type = 1 
    GetBytesFromString = stm.Read 
    Set stm = Nothing 
End Function 
'-- HMACSHA1 ------------------------------------------------------------------' 
Function HMACSHA1(strKey, strValue) 
    Dim sha1: Set sha1 = CreateObject("System.Security.Cryptography.HMACSHA1") 
    sha1.key = GetBytesFromString(strKey) 
    HMACSHA1 = sha1.ComputeHash_2(GetBytesFromString(strValue)) 
    Set sha1 = Nothing 
End Function 
'-- ConvertBytesToBase64 ------------------------------------------------------' 
Function ConvertBytesToBase64(byteValue) 
    Dim dom: Set dom = CreateObject("MSXML2.DomDocument") 
    Dim elm: Set elm = dom.CreateElement("b64") 
    elm.dataType = "bin.base64" 
    elm.nodeTypedValue = byteValue 
    ConvertBytesToBase64 = elm.Text 
    Set elm = Nothing 
    Set dom = Nothing 
End Function 
'-- GetBytesFromFile ----------------------------------------------------------' 
Function GetBytesFromFile(strFileName) 
    Dim stm: Set stm = CreateObject("ADODB.Stream") 
    stm.Type = 1 'adTypeBinary --' 
    stm.Open 
    stm.LoadFromFile strFileName 
    stm.Position = 0 
    GetBytesFromFile = stm.Read 
    stm.Close 
    Set stm = Nothing 
End Function 

Thưa đá-edge-công nghệ-VBScript-bạn tình (*), cho tôi biết nếu nó được làm việc cho bạn như well ;-)

(*) Đây là một tham chiếu ence nhận xét từ Spudley, xem ở trên ;-)