来源申明: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就能看见类似如下的画面 

2585220384.jpg

表明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授权验证代码结束

验证成功消息如下图

482735233.jpg

源码总结如下

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();
	}
}