欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

微信OAuth网页认证 博客分类: 微信WEBoauth 微信oauth 

程序员文章站 2024-03-03 14:52:46
...
    最近要写一个通过微信OAuth协议的网页认证接口,在网上找了一轮,没有找到有什么现成好的代码,就打算自己写算了。

 

首先因为微信的接口都是https的,用HttpClient实现的话因为不清楚是否支持https,所以计划用ajax在客户端完成认证。不过这个绝对是一个十分愚蠢的想法,因为ajax跨域是一个不可逾越的障碍,只不过开始考虑的不周到,直到开始编码的时候才发现,而且还脑袋抽筋的想去解决它,真是耽误不少时间。

 

Ajax行不通以后,逼着使用HttpClient在后台实现了。还是担心HttpClient不支持https,所以在网上看了很久,大部分都是说要导入证书什么的,十分复杂。不过还是迫于无奈,只好找到HttpClient的文档直接就开始实验,发现原来这样访问https HttpClient 是完全支持的,和普通的http没有什么不同,之前的担心多余了,还浪费了好多时间去了解。

 

正式开始,其实微信的认证并不复杂。首先是要调用一个认证URL,引导用户授权(如果有必要),然后微信会回调指定的回调URL,成功的话返回code 参数,通过code就可以继续获取access_token openid,如果之前用户授权的话,还可以获得用户昵称和地址等一些信息。

 

下面是组装认证URL和处理回调的代码,是从一个HttpServlet struts 代码里面直接裁出来的,就是这么个意思而已,编译不过的。

 

第一步,首先要构造一个认证URL,因为这个URL里面包含了回调URL和一个可以带过去的参数,所以一般还是要先自行组装一下。这里面有个地方要注意,state 参数协议里面说是仅支持字母和数字的,所以最好还是用来传一些简单的参数好了,有些人喜欢把一堆参数通过base64加密后放进state 里面传递,但我发现有些情况下还是容易出错,不要冒险的好。

 

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		
		StringBuffer sbrCallbackUrl = new StringBuffer();
		StringBuffer sbrWeiXinAuthUrl = new StringBuffer();
		StringBuffer sbrParamer = new StringBuffer();
		boolean boolFastAuth = false;
		
		int nServerPort = 0;
		
		int nPortalPageId = 0;
		String strToUser = request.getParameter("to_user");
		if (null == strToUser || strToUser.trim().length()<=0) {
			log.error("WeixinWebAuth fail,need ToUser");
			return;
		}
		//这个参数是用来指定是否需要引导用户到授权页面
		String strFastAuth = request.getParameter("fast");
		if (null != strFastAuth ) {
			log.info("Fast auth modle");
			boolFastAuth = true;
		}
		
		String strAppId = "appid";//FIXME
		if (null == strAppId || strAppId.trim().length()<=0) {
			log.error("WeixinWebAuth fail,need appid");
			return;
		}
		String strAppSecret = " AppSecret ";//FIXME
		if (null == strAppSecret || strAppSecret.trim().length()<=0) {
			log.error("WeixinWebAuth fail,need AppSecret");
			return;
		}
		
		sbrParamer.append(PARAM); //FIXME
		
		sbrCallbackUrl.append(request.getScheme()+"://");
		sbrCallbackUrl.append(request.getServerName());
		sbrCallbackUrl.append(CALL_BACK_URL);
		
		//组装认证URL
		sbrWeiXinAuthUrl.append(WEIXIN_WEB_AUTH_URL);
		sbrWeiXinAuthUrl.append("?");
		sbrWeiXinAuthUrl.append("appid=" + strAppId);
		sbrWeiXinAuthUrl.append("&");
		sbrWeiXinAuthUrl.append("redirect_uri=" + java.net.URLEncoder.encode(sbrCallbackUrl.toString(),"UTF-8"));
		sbrWeiXinAuthUrl.append("&");
		sbrWeiXinAuthUrl.append("response_type=code");
		sbrWeiXinAuthUrl.append("&");
		if (!boolFastAuth) {
			sbrWeiXinAuthUrl.append("scope=snsapi_userinfo");
		}
		else {
			sbrWeiXinAuthUrl.append("scope=snsapi_base");
		}
		sbrWeiXinAuthUrl.append("&");
		sbrWeiXinAuthUrl.append("state="+sbrParamer);
		sbrWeiXinAuthUrl.append("#wechat_redirect");
		
		log.info("Goto weixin auth path:" + sbrWeiXinAuthUrl);
		response.sendRedirect(sbrWeiXinAuthUrl.toString());
	}

 

      组装完地址,直接重定向过去。

 

第二步,就是要处理回调过来的信息。这个其实也比较简单。

 

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class WeixinWebAuthCallbackAction extends Action {
	private final String strAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
	private final String strGetUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo";
	
    @Override
    protected ActionForward executeAction(ActionMapping mapping,
            ActionForm actionForm, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

    	response.setContentType("text/html");
    	response.setCharacterEncoding("UTF-8");
    	
    	String strWeixinCallbackCode = null;
    	String strParamers = null;
    	
        log.info("微信web认证获取帐号开始");

        strWeixinCallbackCode = request.getParameter("code");
        log.info("return code:" + strWeixinCallbackCode);
        strParamers = request.getParameter("state");
        log.info("return :" + strParamers);

        if (null == strWeixinCallbackCode || strWeixinCallbackCode.equals("authdeny") 
        		|| null == strParamers || strParamers.isEmpty()) {
            log.info("用户拒绝授权");
            request.setAttribute("errcode", 1);
            request.setAttribute("errmsg", "用户拒绝授权");				
            return mapping.findForward("fail");
        }
        
        String strAccessToken = null;
        String strUserOpenId = null;

		String strNickName = "";
		String strSex = "";//1 man;2 female;3 unknown;
        String address = "";

        String strAppId = "AppId";//FIXME
        String strAppSecret = "AppSecret";//FIXME
		
        Map<String, String> mapAccessToken = getAccessTokenAndUid(strWeixinCallbackCode, strAppId, strAppSecret);
        if (null == mapAccessToken || null != mapAccessToken.get("errcode")) {
            log.info("获取访问token错误");
            if (null != mapAccessToken) {
	            request.setAttribute("errcode", mapAccessToken.get("errcode"));
	            request.setAttribute("errmsg", mapAccessToken.get("errmsg"));				
			}
            return mapping.findForward("fail");
        }
        strAccessToken = mapAccessToken.get("access_token");
        strUserOpenId = mapAccessToken.get("openid");
        Map<String, String> mapUserInfo = getUserInfo(strAccessToken, strUserOpenId);        
		if (null != mapUserInfo) {
	        if(null != mapUserInfo.get("errcode")){
	            log.info("获取用户信息错误");
	            request.setAttribute("errcode", mapUserInfo.get("errcode"));
	            request.setAttribute("errmsg", mapUserInfo.get("errmsg"));
		        return mapping.findForward("fail");
	        }
	        strNickName = mapUserInfo.get("nickname");
	        strSex = mapUserInfo.get("sex");
		}
               
        log.info("weixin web auth,user:"+strNickName+" sex:"+strSex);
        
        return mapping.findForward("success");
        
    }
    
    private Map<String , String> getAccessTokenAndUid(String strCode,String strAppId,String strAppSecret){
        String responseDate = "" ;
        Map<String , String> token = null;

        PostMethod postMethod = new PostMethod(strAccessTokenUrl);
        postMethod.addParameter("appid", strAppId);
        postMethod.addParameter("secret",strAppSecret);
        postMethod.addParameter("code",strCode);
        postMethod.addParameter("grant_type","authorization_code");
        
        HttpClient client = new HttpClient();
        try {
            client.executeMethod(postMethod);
            responseDate = postMethod.getResponseBodyAsString();
        } catch (Exception e) {
        	log.error(e.getMessage());
            e.printStackTrace();
        }
        
        if(responseDate.trim().length()>0){
            token = new HashMap<String, String>();
            JSONObject jsonData = JSONObject.fromObject(responseDate);
            if (jsonData.has("errcode")) {
				log.error("Get access token fail,reason:" + jsonData.getString("errmsg"));
				token.put("errcode", jsonData.getString("errcode"));
				token.put("errmsg", jsonData.getString("errmsg"));
				return null;
			}
            
            log.info("Get access_token:"+jsonData.getString("access_token")+";openid:"+jsonData.getString("openid"));
            token.put("access_token", jsonData.getString("access_token"));
            token.put("openid", jsonData.getString("openid"));
        }
        return  token;
    }
    
    
    private Map<String , String> getUserInfo(String strAccessToken,String strOpenId){
        String responseDate = "" ;
        Map<String , String> token = null;

        PostMethod postMethod = new PostMethod(strGetUserInfoUrl);
        postMethod.addParameter("access_token", strAccessToken);
        postMethod.addParameter("openid",strOpenId);
        postMethod.addParameter("lang","zh_CN");
        
        HttpClient client = new HttpClient();
        try {
            client.executeMethod(postMethod);
            responseDate = postMethod.getResponseBodyAsString();
        } catch (Exception e) {
        	log.error(e.getMessage());
            e.printStackTrace();
        }
        if(responseDate.trim().length()>0){
            token = new HashMap<String, String>();
            JSONObject jsonData = JSONObject.fromObject(responseDate);
            if (jsonData.has("errcode")) {
				log.info("Get user info fail,reason:["+jsonData.getString("errcode")+ "]" + jsonData.getString("errmsg"));
			//这个是没用户授权,不能取用户信息的返回错误码,文档没提及,随时可能变的
            	if (48001 == jsonData.getLong("errcode")) {
            		log.info("Can't get userinfo,but wo can continue.");
					return null;
				}
				token.put("errcode", jsonData.getString("errcode"));
				token.put("errmsg", jsonData.getString("errmsg"));
				return token;
			}
            
            if (!jsonData.has("openid") || !jsonData.has("nickname")) {
            	log.info("No user info available");
				return null;
			}
            log.info("weixin web auth,user:"+jsonData.getString("nickname")+" sex:"+jsonData.getString("sex")
            		+ " province:"+jsonData.getString("province")+" city:"+jsonData.getString("city")
            		+ " country:"+jsonData.getString("country"));
            
            token.put("openid", jsonData.getString("openid"));
            token.put("nickname", jsonData.getString("nickname"));
            token.put("sex", jsonData.getString("sex"));
            token.put("province", jsonData.getString("province"));
            token.put("city", jsonData.getString("city"));
            token.put("country", jsonData.getString("country"));
        }
        return  token;
    }
}

 

 

 

 

 

相关标签: 微信 oauth