在IMS模拟器(http://ltiapps.net/test/tc.php)中单击“保存数据”时,使用自动填充的数据生成outh_signature并将其作为隐藏值以frmLaunch(name ='frmLaunch')形式输入。我需要以编程方式生成类似的outh_signature,但是我无法生成精确的oauth_signature,即使我使用相同的oauth_nounce和oauth_timestamp,模拟器也会生成什么..我不确定生成时需要发送的请求体是什么签名..
要重新创建方案,请按照以下步骤进行操作
保存数据后,您会看到一个outh_signature隐藏值,输入ID为“oauth_signature”
我尝试以下面的方式生成但无法获得预期的签名。
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
// Apache Commons Libraries used for the Nonce & Base64
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
public class OAuthTest {
public static void main(final String[] args) throws Exception
{
// Setup the variables necessary to create the OAuth 1.0 signature and make the request
String httpMethod = "POST";
String consumerKey = "jisc.ac.uk";
String secret = "secret";
String signatureMethod = "HMAC-SHA1";
String body = ""; //mentioned in the description
byte[] requestBody = null;
URL url = new URL("http://ltiapps.net/test/tp.php");
// Set the Nonce and Timestamp parameters
String nonce = "6d95eef168e568a530d1cd419a997952";//getNonce();
String timestamp = "1483470400";//getTimestamp();
System.out.println("Nonce:" + getNonce());
System.out.println("timestamp:" + getTimestamp());
// Set the request body if making a POST or PUT request
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod))
{
requestBody = body.getBytes("UTF-8");
}
// Create the OAuth parameter name/value pair
Map<String, String> oauthParams = new LinkedHashMap<String, String>();
oauthParams.put("oauth_consumer_key", consumerKey);
oauthParams.put("oauth_signature_method", signatureMethod);
oauthParams.put("oauth_timestamp", timestamp);
oauthParams.put("oauth_nonce", nonce);
// Get the OAuth 1.0 Signature
String signature = generateSignature(httpMethod, url, oauthParams, requestBody, secret);
System.out.println(String.format("OAuth 1.0 Signature: %s", signature));
}
private static String getNonce()
{
return RandomStringUtils.randomAlphanumeric(32);
}
private static String getTimestamp()
{
return Long.toString((System.currentTimeMillis() / 1000));
}
private static String generateSignature(
String httpMethod,
URL url,
Map<String, String> oauthParams,
byte[] requestBody,
String secret
) throws UnsupportedEncodingException
{
// Ensure the HTTP Method is upper-cased
httpMethod = httpMethod.toUpperCase();
// Construct the URL-encoded OAuth parameter portion of the signature base string
String encodedParams = normalizeParams(httpMethod, url, oauthParams, requestBody);
// URL-encode the relative URL
String encodedUri = URLEncoder.encode(url.getPath(), "UTF-8");
// Build the signature base string to be signed with the Consumer Secret
String baseString = String.format("%s&%s&%s", httpMethod, encodedUri, encodedParams);
return hmacSha1(baseString, secret);
}
private static String normalizeParams(
String httpMethod,
URL url,
Map<String, String> oauthParams,
byte[] requestBody
) throws UnsupportedEncodingException
{
// Sort the parameters in lexicographical order, 1st by Key then by Value
Map<String, String> kvpParams = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
kvpParams.putAll(oauthParams);
// Place any query string parameters into a key value pair using equals ("=") to mark
// the key/value relationship and join each parameter with an ampersand ("&")
if (url.getQuery() != null)
{
for(String keyValue : url.getQuery().split("&"))
{
String[] p = keyValue.split("=");
kvpParams.put(p[0],p[1]);
}
}
// Include the body parameter if dealing with a POST or PUT request
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod))
{
String body = Base64.encodeBase64String(requestBody).replaceAll("\r\n", "");
// url encode the body 2 times now before combining other params
body = URLEncoder.encode(body, "UTF-8");
body = URLEncoder.encode(body, "UTF-8");
kvpParams.put("body", body);
}
// separate the key and values with a "="
// separate the kvp with a "&"
StringBuilder combinedParams = new StringBuilder();
String delimiter="";
for(String key : kvpParams.keySet()) {
combinedParams.append(delimiter);
combinedParams.append(key);
combinedParams.append("=");
combinedParams.append(kvpParams.get(key));
delimiter="&";
}
// url encode the entire string again before returning
return URLEncoder.encode(combinedParams.toString(), "UTF-8");
}
public static String hmacSha1(String value, String key) {
String algorithm = "HmacSHA1";
try {
// Get an hmac_sha1 key from the raw key bytes
byte[] keyBytes = key.getBytes();
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, algorithm);
// Get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(algorithm);
mac.init(signingKey);
// Compute the hmac on input data bytes
// byte[] rawHmac = mac.doFinal(value.getBytes());
// Convert raw bytes to Hex
// byte[] hexBytes = new Hex().encode(rawHmac);
return new String(Base64.encodeBase64(mac.doFinal(value.getBytes()))).trim();
// Covert array of Hex bytes to a String
//return new String(hexBytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
的pom.xml
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
</dependency>
我通过发送以下请求体来尝试上述程序并获得outh签名为 0YI3mBg7gmnWaz8YyISG4IoHVQ4 = 但预期 yuuvR1pVDm5xWOYhMtBcBBVTdf8 =
能告诉我出错的地方吗?
答案 0 :(得分:1)
由于您使用的是JAVA,我建议您使用IMSGlobal提供的basiclti-util库,它会处理您正在做的大部分内容,并且不需要您重新发明轮子
将以下依赖项添加到您的pom
<dependency>
<groupId>org.imsglobal</groupId>
<artifactId>basiclti-util</artifactId>
<version>1.1.2</version>
</dependency>
此库提供以下支持:
工具提供商:
工具消费者:
验证工具消费者发送的LTI启动请求
HttpServletRequest request; // java servlet request
LtiVerifier ltiVerifier = new LtiOauthVerifier();
String key = request.getParameter("oauth_consumer_key");
String secret = // retrieve corresponding secret for key from db
LtiVerificationResult ltiResult = ltiVerifier.verify(request, secret);
如果您尝试签署传出请求,请使用以下
Map<String, String> signedParameters = new LtiOauthSigner().signParameters(parameters, key, secret, url, "POST");