![cover](https://image.oss.salted-fish.tech/blog/2585220384.jpg)
Steam第三方登陆
来源申明:https://weibo.com/p/1001603922680121320645
生成跳转到Steam登录页面的源码开始
//Steam使用openid登录的网址
final static String STEAM_LOGIN = "https://steamcommunity.com/openid/login";
public static String getUrl(String returnTo) throws UnsupportedEncodingException {
Map<String, String> params = new HashMap<String, String>();
params = new HashMap<String, String>();
params.put("openid.ns", "//specs.openid.net/auth/2.0");
params.put("openid.mode", "checkid_setup");
//登陆成功后要返回url,值得一说的是这个url是可以携带参数的
params.put("openid.return_to", returnTo);
//realm的中文解释是领域与范围,我想大概就是你网站域名,授权用户登录你域名下的应用,我这里默认就用传过来的returnTo了
params.put("openid.realm", returnTo);
params.put("openid.identity",
"//specs.openid.net/auth/2.0/identifier_select");
params.put("openid.claimed_id",
"//specs.openid.net/auth/2.0/identifier_select");
return STEAM_LOGIN + "?" + SteamLoginUtil.getUrlParamsByMap(params);
}
/**
* 将url中传递参数转化为map 其中值进行encode
*
* @param param
* aa=11&bb=22&cc=33
* @return
* @throws UnsupportedEncodingException
*/
public static Map<String, String> getUrlParams(String param) throws UnsupportedEncodingException {
Map<String, String> map = new HashMap<String, String>(0);
if (StringUtils.isBlank(param)) {
return map;
}
String[] params = param.split("&");
for (int i = 0; i < params.length; i++) {
String[] p = params[ i ].split("=");
if (p.length == 2) {
map.put(p[0], URLDecoder.decode(p[ 1 ],"UTF-8"));
}
}
return map;
}
生成跳转到Steam登录页面的源码结束
OK,用上述的代码,传入一个returnTo的参数,就生成一串URL。浏览器打开这个URL就能看见类似如下的画面
表明Steam可以授权给你登录,只要用户登录成功,steam就会跳转到你设置的returnTo地址,并且携带一大波参数。
虽然返回给你了这些参数,用户还不能立即得到登录授权,为什么呢(如果我现在直接给你授权,我返回给你的参数都是明文的,那岂不是任何一个人都能伪造出这么一串参数来登录你的系统,你咋能放心呢)。其实这个时候openid的机制已经记住了这个用户要登录你的系统,但是你的系统还要确认一下,跟openID说这个用户确实是从我这里发出来的登录请求,我请求你允许他登录我的系统。
怎样“请求你~允许他~登录我的系统”呢?
这里用了HttpClient去请求openid的提供者。这个过程用户是看不到的,透明的。
就相当于你的网站和openid提供者说了句悄悄话。说的就是“请求你~允许他~登录我的系统”。而openid的提供者一查,这用户刚才亮出了身份,确实跟我过说要登录你的系统,OK给你俩授权。你俩自己聊去吧!
过程是这样,代码在这里。
HttpClient授权验证代码
/**
* 将steam返回的request参数再次提交steam进行授权,检查是否成功登录,返回steamid算成功,返回空字符串为不成功
*
* @param request
* @return boolean
* @throws ClientProtocolException
* @throws IOException
*/
public static String validate(Map<String,String> request) throws ClientProtocolException, IOException{
//openid.signed这里面的参数用是“,”号隔开的,是提示你返回了哪些参数
Object signed = request.get("openid.signed");
//如果没有openid.signed,那肯定这个请求是不正确的直接跳出即可
if(signed ==null || "".equals(signed)){
return "";
}
//此处开始构造HttpClient对象,配置参数,设置访问方法,获取返回值等,进行一次完整访问
HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost(STEAM_LOGIN+"?"+SteamLoginUtil.getUrlParamsByMap(request));
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
String[] signeds = signed.toString().split(",");
for(int i=0;i<signeds.length;i++){
String val = request.get("openid."+signeds[ i ]);
nvps.add(new BasicNameValuePair("openid."+signeds[ i ], val==null?"":val));
}
nvps.add(new BasicNameValuePair("openid.mode", "check_authentication"));
httppost.setEntity(new UrlEncodedFormEntity(nvps));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity == null) {
return "";
}
InputStream instreams = entity.getContent();
String result = SteamLoginUtil.convertStreamToString(instreams);
//System.out.println("Do something");
System.out.println(result);
// Do not need the rest
httppost.abort();
//此处是为了将steamid截取出来
String steamid = "";
steamid = request.get("openid.claimed_id");
steamid = steamid.replace("//steamcommunity.com/openid/id/","");
//虽然steamid能从上一次请求参数中截取出来,我们还是要判断HttpClient返回来的消息是否授权了,判断方式是看字符串中是否含有“is_valid:true”,有就是授权成功了,如果没有,就是“is_valid:false”。
if(!result.contains("is_valid:true")){
return "";
}
return steamid;
}
/**
* 将输入流读取为一串字符串
* @param is
* @return
*/
public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
HttpClient授权验证代码结束
验证成功消息如下图
源码总结如下
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringUtils {
public static String parseWhereString (HashMap<String, Object> params,String alias){
StringBuffer buffer = new StringBuffer();
if(params == null || params.isEmpty()){
return "";
}else{
buffer.append(" where ");
Set<Entry<String, Object>> set = params.entrySet();
Iterator<Entry<String, Object>> iterator = set.iterator();
Entry<String, Object> entry = null;
while(iterator.hasNext()){
buffer.append(" and ");
entry = iterator.next();
buffer.append(alias);
if (!alias.equals("")) {
buffer.append(".");
}
buffer.append(entry.getKey());
buffer.append("=");
buffer.append(" ? ");
entry = null;
}
iterator = null;
String temp = buffer.toString();
int location = temp.indexOf("and");
buffer = new StringBuffer();
buffer.append(temp.substring(0, location));
buffer.append(temp.substring(location+4));
temp = null;
return buffer.toString();
}
}
/**
* 去掉开头结尾制定字符串
* @param stream
* @param trimstr
* @return
*/
public static String sideTrim(String stream, String trimstr) {
// null或者空字符串的时候不处理
if (stream == null || stream.length() == 0 || trimstr == null || trimstr.length() == 0) {
return stream;
}
// 结束位置
int epos = 0;
// 正规表达式
String regpattern = "[" + trimstr + "]*+";
Pattern pattern = Pattern.compile(regpattern, Pattern.CASE_INSENSITIVE);
// 去掉结尾的指定字符
StringBuffer buffer = new StringBuffer(stream).reverse();
Matcher matcher = pattern.matcher(buffer);
if (matcher.lookingAt()) {
epos = matcher.end();
stream = new StringBuffer(buffer.substring(epos)).reverse().toString();
}
// 去掉开头的指定字符
matcher = pattern.matcher(stream);
if (matcher.lookingAt()) {
epos = matcher.end();
stream = stream.substring(epos);
}
// 返回处理后的字符串
return stream;
}
/**
* <p>Checks if a String is whitespace, empty ("") or null.</p>
*
* <pre>
* StringUtils.isBlank(null) = true
* StringUtils.isBlank("") = true
* StringUtils.isBlank(" ") = true
* StringUtils.isBlank("bob") = false
* StringUtils.isBlank(" bob ") = false
* </pre>
*
* @param str the String to check, may be null
* @return <code>true</code> if the String is null, empty or whitespace
* @since 2.0
*/
public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}
/**
* <p>Gets the substring before the last occurrence of a separator.
* The separator is not returned.</p>
*
* <p>A <code>null</code> string input will return <code>null</code>.
* An empty ("") string input will return the empty string.
* An empty or <code>null</code> separator will return the input string.</p>
*
* <pre>
* StringUtils.substringBeforeLast(null, *) = null
* StringUtils.substringBeforeLast("", *) = ""
* StringUtils.substringBeforeLast("abcba", "b") = "abc"
* StringUtils.substringBeforeLast("abc", "c") = "ab"
* StringUtils.substringBeforeLast("a", "a") = ""
* StringUtils.substringBeforeLast("a", "z") = "a"
* StringUtils.substringBeforeLast("a", null) = "a"
* StringUtils.substringBeforeLast("a", "") = "a"
* </pre>
*
* @param str the String to get a substring from, may be null
* @param separator the String to search for, may be null
* @return the substring before the last occurrence of the separator,
* <code>null</code> if null String input
* @since 2.0
*/
public static String substringBeforeLast(String str, String separator) {
if (isEmpty(str) || isEmpty(separator)) {
return str;
}
int pos = str.lastIndexOf(separator);
if (pos == -1) {
return str;
}
return str.substring(0, pos);
}
// Empty checks
//-----------------------------------------------------------------------
/**
* <p>Checks if a String is empty ("") or null.</p>
*
* <pre>
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty("") = true
* StringUtils.isEmpty(" ") = false
* StringUtils.isEmpty("bob") = false
* StringUtils.isEmpty(" bob ") = false
* </pre>
*
* <p>NOTE: This method changed in Lang version 2.0.
* It no longer trims the String.
* That functionality is available in isBlank().</p>
*
* @param str the String to check, may be null
* @return <code>true</code> if the String is empty or null
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
public class SteamLoginUtil {
final static String STEAM_LOGIN = "https://steamcommunity.com/openid/login";
/**
* 接入steam登录url
*
* @param returnTo
* @param request
* @return
* @throws UnsupportedEncodingException
*/
public static String getUrl(String returnTo) throws UnsupportedEncodingException {
Map<String, String> params = new HashMap<String, String>();
params = new HashMap<String, String>();
// String loginTicket = request.getAttribute("loginTicket")==null ? "" :
// "?lt="+ request.getAttribute("loginTicket").toString();
// params.put("lt", request.getAttribute("loginTicket")==null
// ?"":request.getAttribute("loginTicket").toString());
params.put("openid.ns", "http://specs.openid.net/auth/2.0");
params.put("openid.mode", "checkid_setup");
params.put("openid.return_to", returnTo);
params.put("openid.realm", returnTo);
params.put("openid.identity", "http://specs.openid.net/auth/2.0/identifier_select");
params.put("openid.claimed_id", "http://specs.openid.net/auth/2.0/identifier_select");
return STEAM_LOGIN + "?" + SteamLoginUtil.getUrlParamsByMap(params);
}
/**
* 将数据提交steam进行验证,是否成功登录
*
* @param request
* @return boolean
* @throws ClientProtocolException
* @throws IOException
*/
public static String validate(Map<String, String> request){
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setSocketTimeout(5000)
.setConnectTimeout(5000)
.setConnectionRequestTimeout(5000)
.build();
CloseableHttpClient httpclient = null;
HttpPost httppost = null;
try {
Object signed = request.get("openid.signed");
if (signed == null || "".equals(signed)) {
return "";
}
httpclient = HttpClients.createDefault();
httppost = new HttpPost(STEAM_LOGIN + "?" + SteamLoginUtil.getUrlParamsByMap(request));
httppost.setConfig(defaultRequestConfig);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
String[] signeds = signed.toString().split(",");
for (int i = 0; i < signeds.length; i++) {
String val = request.get("openid." + signeds[i]);
nvps.add(new BasicNameValuePair("openid." + signeds[i], val == null ? "" : val));
}
nvps.add(new BasicNameValuePair("openid.mode", "check_authentication"));
httppost.setEntity(new UrlEncodedFormEntity(nvps));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity == null) {
return "";
}
InputStream instreams = entity.getContent();
String result = SteamLoginUtil.convertStreamToString(instreams);
// Do not need the rest
httppost.abort();
String steamid = "";
steamid = request.get("openid.claimed_id");
steamid = steamid.replace("https://steamcommunity.com/openid/id/", "");
if (!result.contains("is_valid:true")) {
return "";
}
return steamid;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(httppost != null){
httppost.releaseConnection();
}
if(httpclient != null){
try {
httpclient.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return "";
}
/**
* 将url中传递参数转化为map 其中值进行encode
*
* @param param
* aa=11&bb=22&cc=33
* @return
* @throws UnsupportedEncodingException
*/
public static Map<String, String> getUrlParams(String param) throws UnsupportedEncodingException {
Map<String, String> map = new HashMap<String, String>(0);
if (StringUtils.isBlank(param)) {
return map;
}
String[] params = param.split("&");
for (int i = 0; i < params.length; i++) {
String[] p = params[i].split("=");
if (p.length == 2) {
map.put(p[0], URLDecoder.decode(p[1], "UTF-8"));
}
}
return map;
}
/**
* 将map转化为url可携带的参数字符串
*
* @param map
* @return
* @throws UnsupportedEncodingException
*/
public static String getUrlParamsByMap(Map<String, String> map) throws UnsupportedEncodingException {
if (map == null) {
return "";
}
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : map.entrySet()) {
// 解码
sb.append(entry.getKey() + "=" + URLEncoder.encode(entry == null ? "" : entry.getValue(), "UTF-8"));
sb.append("&");
}
String s = sb.toString();
if (s.endsWith("&")) {
s = StringUtils.substringBeforeLast(s, "&");
}
return s;
}
public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 Salted Fish
评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果