1. 程式人生 > >微信開發五: 網頁授權

微信開發五: 網頁授權

微信開發文件:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

構造到授權的網頁連結

使用方式:例

 // new baseservice().BuildAuthCallbackUrl("/mydemo/product/ProductDetails?id="+product.getId(), EnumScopeType.snsapi_userinfo);

package com.star.wxservice;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

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

import org.apache.log4j.Logger;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.star.etmvcfilters.BaseServcie;
import com.star.model.UserSessionUtil;
import com.star.model.Wechat_User;
import com.star.utils.Cache;
import com.star.utils.CacheManager;
import com.star.utils.HttpRequestUtil;
import com.star.utils.JsonMapper;
import com.star.wxmessagemodel.EnumScopeType;
import com.star.wxmessagemodel.OpenIdResult;
import com.star.wxmessagemodel.RefreshtokenResult;
import com.star.wxmessagemodel.TokenJsonResult;
import com.star.wxmessagemodel.WechatUserInfo;

import config.Property;

public class baseservice {

    private static Logger logger = Logger.getLogger(baseservice.class);

    private static final String WECHAR_PATH = "/config/wechat.properties";

    public static final String WECHAT_APPID = Property.GetXMLValuesByKey(WECHAR_PATH, "WECHAT_APPID");

    public static final String WECHAT_SECRET = Property.GetXMLValuesByKey(WECHAR_PATH, "WECHAT_SECRET");

    private static final String Web_PATH = "/config/web.properties";

    /**
     * 當前域名
     */
    public static String ServerName = Property.GetXMLValuesByKey(Web_PATH, "ServerName");

    /**
     * 獲取每次操作微信API的Token訪問令牌
     * 
     * @return <param name="appid">應用ID</param>
     *         <param name="secret">開發者憑據</param>
     * @throws Exception
     */
    public String GetAccessToken() throws Exception {
        String key = "weixin.accesstoken";
        // 正常情況下access_token有效期為7200秒,這裡使用快取設定短於這個時間即可

        String token = "";

        if (CacheManager.getCacheInfo(key) == null) {
            String grant_type = "client_credential";
            String url = "https://api.weixin.qq.com/cgi-bin/token";
            String para = String.format("grant_type=%s&appid=%s&secret=%s", grant_type, WECHAT_APPID, WECHAT_SECRET);
            String jsonStr = HttpRequestUtil.sendGet(url, para);
            TokenJsonResult jsonObject = JsonMapper.json2Bean(jsonStr, TokenJsonResult.class);

            Cache cache = new Cache();
            cache.setKey("accesstoken");
            cache.setValue(jsonObject.getAccess_token());
            cache.setTimeOut(7000);
            cache.setExpired(false);

            CacheManager.putCache(key, cache);

            return jsonObject.getAccess_token();
        } else {
            return CacheManager.getCacheInfo(key).getValue().toString();
        }
    }

    /**
     * 獲取openId
     * 
     * @param code
     * @return
     * @throws Exception
     */
    public OpenIdResult GetOpenId(String code) throws Exception {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token";
        String para = String.format("appid=%s&secret=%s&code=%s&grant_type=authorization_code", WECHAT_APPID,
                WECHAT_SECRET, code);
        String jsonStr = HttpRequestUtil.sendGet(url, para);

        OpenIdResult result = JsonMapper.json2Bean(jsonStr, OpenIdResult.class);

        return result;
    }

    /**
     * 獲取微信使用者基本資訊 -靜默授權
     * 
     * @param openId
     * @return
     * @throws Exception
     */
    public WechatUserInfo GetUserInfo(String openId) throws Exception {
        logger.error("OPENID=============================================" + openId);

        String url = "https://api.weixin.qq.com/cgi-bin/user/info";
        String para = String.format("access_token=%s&openid=%s&lang=zh_CN", GetAccessToken(), openId);
        String jsonStr = HttpRequestUtil.sendGet(url, para);
        // jsonStr = new String(jsonStr.getBytes("ISO-8859-1"), "UTF-8");
        logger.error("OPENID---jsonStr  =============================================" + jsonStr);
        WechatUserInfo model = JsonMapper.json2Bean(jsonStr, WechatUserInfo.class);
        return model;
    }

    /// <summary>
    /// 構造URL
    /// </summary>
    /// <param name="pathAndQuery"></param>
    /// <returns></returns>
    public String GetUrl(String pathAndQuery) {
        return String.format("%s%s", ServerName, pathAndQuery);// pathAndQuery.TrimStart('/')
    }

    /**
     * 構造微信通用授權URL
     * 
     * @param redirectUrl
     *            授權後跳轉的頁面
     * @param state
     *            自定義函式
     * @param scope
     *            授權型別 :snsapi_base 靜默授權, snsapi_userinfo手動同意授權
     * @return
     */
    public String BuildAuthUrl(String redirectUrl, String state, String scope) {
        String apiUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
        try {
            redirectUrl = java.net.URLEncoder.encode(redirectUrl, "utf-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return String.format(apiUrl, WECHAT_APPID, redirectUrl, scope, state);
    }

    /**
     * 構造授權回撥地址
     * 
     * @param type
     *            頁面型別
     * @param scope
     *            授權型別 :snsapi_base 靜默授權, snsapi_userinfo手動同意授權
     * @return
     */
    public String BuildAuthCallbackUrl(String returnUrl, EnumScopeType scope) {
        String url = BuildAuthUrl(GetUrl(String.format("/yeewii.m/WXApi/Auth?action=%s", returnUrl)), "state",
                scope.toString());// Guid.NewGuid().ToString().Replace("-",
        System.out.println("============================="); // "") // //
        System.out.println(url); // "")
        return url;
    }

    /// <summary>
    /// 登入,若使用者存在,則返回登入後的使用者資訊,否則返回null
    /// </summary>
    /// <param name="openId"></param>
    /// <returns></returns>
    public Wechat_User LoginInternal(HttpServletRequest request, HttpServletResponse response, String openId,
            WechatUserInfo wxUser) throws Exception {

        UserSessionUtil session = new UserSessionUtil();
        session.setHeadimgurl(wxUser != null ? wxUser.headimgurl : "");
        session.setNickname(wxUser != null ? wxUser.nickname : "");
        session.setOpenId(wxUser != null ? wxUser.openid : "");

        request.getSession().setAttribute("wxUser", session);

        Wechat_User webchatuser = Wechat_User.findFirst(Wechat_User.class, "openid=?", new Object[] { openId });
        if (webchatuser != null) {
            BaseServcie.sendAutoLoginCookie(request, response, webchatuser);
        }
        return webchatuser;
    }

    /**
     * 重新整理access_token(如果需要)
     * 
     * @param refresh_token
     * @return
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     */
    public RefreshtokenResult Refreshtoken(String refresh_token)
            throws JsonParseException, JsonMappingException, IOException {
        String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
        String para = String.format("appid=%s&grant_type=refresh_token&refresh_token=%s", WECHAT_APPID, refresh_token);
        String jsonStr = HttpRequestUtil.sendGet(url, para);

        RefreshtokenResult result = JsonMapper.json2Bean(jsonStr, RefreshtokenResult.class);
        return result;
    }

    /**
     * 獲取微信使用者基本資訊 -手動授權
     * 
     * @param openId
     * @param accessToken
     * @param refresh_token
     * @return
     * @throws Exception
     * @throws JsonMappingException
     * @throws IOException
     */
    public WechatUserInfo GetSnsapiUserinfo(String openId, String accessToken, String refresh_token)
            throws Exception, JsonMappingException, IOException {
        String url = "https://api.weixin.qq.com/sns/userinfo";
        RefreshtokenResult toRefreshtokenResult = Refreshtoken(refresh_token);

        String para = String.format("access_token=%s&openid=%s&lang=zh_CN", accessToken, openId);
        String jsonStr = HttpRequestUtil.sendGet(url, para);
        WechatUserInfo result = JsonMapper.json2Bean(jsonStr, WechatUserInfo.class);
        return result;
        // 在獲取使用者資訊時,提示,"errcode": 48001, 介面未被授權
        // 需要使用者提升為服務號,並且進行認證繳交每年300元
    }

    /**
     * 最底層字串編碼轉換的實現方法
     * 
     * @param str
     *            待轉換的字串
     * @param oldCharset
     *            源字符集
     * @param newCharset
     *            目標字符集
     * @return 轉換後的字串
     */
    public String changeCharset(String str, String oldCharset, String newCharset) {
        if (str != null) {
            // 用源字元編碼解碼字串
            try {
                return new String(str.getBytes(oldCharset), newCharset);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}


相關轉換實體類

package com.star.wxmessagemodel;

public enum EnumScopeType {

    /**
     * 靜默授權
     */
    snsapi_base,

    /**
     * 需手動同意授權
     */
    snsapi_userinfo,

}
package com.star.wxmessagemodel;

public class OpenIdResult {

    public String access_token;

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(String expires_in) {
        this.expires_in = expires_in;
    }

    public String getRefresh_token() {
        return refresh_token;
    }

    public void setRefresh_token(String refresh_token) {
        this.refresh_token = refresh_token;
    }

    public String getOpenid() {
        return openid;
    }

    public void setOpenid(String openid) {
        this.openid = openid;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public String getErrcode() {
        return errcode;
    }

    public void setErrcode(String errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

    public String expires_in;

    public String refresh_token;

    public String openid;

    public String scope;

    public String errcode;

    public String errmsg;

    public String unionid;

    public String getUnionid() {
        return unionid;
    }

    public void setUnionid(String unionid) {
        this.unionid = unionid;
    }

}

package com.star.wxmessagemodel;

/**
 * 重新整理access_token(如果需要)
 * 由於access_token擁有較短的有效期,當access_token超時後,可以使用refresh_token進行重新整理,refresh_token擁有較長的有效期(7天、30天、60天、90天),當refresh_token失效的後,需要使用者重新授權。
 * 
 * @author Administrator
 *
 */
public class RefreshtokenResult {

    public String access_token;

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(String expires_in) {
        this.expires_in = expires_in;
    }

    public String getRefresh_token() {
        return refresh_token;
    }

    public void setRefresh_token(String refresh_token) {
        this.refresh_token = refresh_token;
    }

    public String getOpenid() {
        return openid;
    }

    public void setOpenid(String openid) {
        this.openid = openid;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public String expires_in;

    public String refresh_token;

    public String openid;

    public String scope;

}

package com.star.wxmessagemodel;

public class TicketResult {

    public String errcode;

    public String getErrcode() {
        return errcode;
    }

    public void setErrcode(String errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

    public String getTicket() {
        return ticket;
    }

    public void setTicket(String ticket) {
        this.ticket = ticket;
    }

    public String getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(String expires_in) {
        this.expires_in = expires_in;
    }

    public String errmsg;

    public String ticket;

    public String expires_in;
}
package com.star.wxmessagemodel;

public class TokenJsonResult {

    public String access_token;

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(String expires_in) {
        this.expires_in = expires_in;
    }

    public String getErrcode() {
        return errcode;
    }

    public void setErrcode(String errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

    public String expires_in;

    public String errcode;

    public String errmsg;

}

cache
package com.star.utils;

public class Cache {
    private String key;// 快取ID

    private Object value;// 快取資料

    private long timeOut;// 更新時間

    private boolean expired; // 是否終止

    public Cache() {
        super();
    }

    public Cache(String key, Object value, long timeOut, boolean expired) {
        this.key = key;
        this.value = value;
        this.timeOut = timeOut;
        this.expired = expired;
    }

    public String getKey() {
        return key;
    }

    public long getTimeOut() {
        return timeOut;
    }

    public Object getValue() {
        return value;
    }

    public void setKey(String string) {
        key = string;
    }

    public void setTimeOut(long l) {
        timeOut = l;
    }

    public void setValue(Object object) {
        value = object;
    }

    public boolean isExpired() {
        return expired;
    }

    public void setExpired(boolean b) {
        expired = b;
    }
}


回撥地址 (獲取使用者資訊) 返回到指定頁面
/**
     * 回撥地址 (登入操作,獲取使用者資訊) 返回到指定頁面
     * 
     * @param code
     * @param state
     * @return
     * @throws Exception
     */
    public JspView Auth(String code, String state) throws Exception {
        String targetUrl = "";
        Wechat_User user = new Wechat_User();
        String openId = "";
        try {
            targetUrl = request.getParameter("action");

            // String actionValue = request.getParameter("action");

            // // 也可以這樣判斷 是否在其中
            // //
            // Arrays.asList(EnumWechatMenuType.values()).contains(actionValue);
            // if (!EnumWechatMenuType.IsIndexfoNo(actionValue)) {
            // // String.format("微信授權回撥錯誤,未知的動作:{0}.", actionValue)
            // }

            baseservice baseService = new baseservice();
            OpenIdResult openresult = baseService.GetOpenId(code);
            openId = openresult.getOpenid();
            String accessToken = openresult.getAccess_token();
            String refresh_token = openresult.getRefresh_token();

            // WechatUserInfo wxUser = baseService.GetUserInfo(openId);//
            // //
            // 以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的使用者的openid的,並且是靜默授權並自動跳轉到回撥頁的。使用者感知的就是直接進入了回撥頁(往往是業務頁面)

            WechatUserInfo wxUser = baseService.GetSnsapiUserinfo(openId, accessToken, refresh_token);
            //
            // 以snsapi_userinfo為scope發起的網頁授權,是用來獲取使用者的基本資訊的。但這種授權需要使用者手動同意,並且由於使用者同意過,所以無須關注,就可在授權後獲取該使用者的基本資訊。
            user = baseService.LoginInternal(request, response, openId, wxUser);

            // for (EnumWechatMenuType name : EnumWechatMenuType.values()) {
            // if (name.toString().equals(actionValue)) {
            // targetUrl = name.getReturnurl();
            // break;
            // }
            // }
            if (user == null) {
                Map<String, Object> map = new Wechat_UserDao().do_Wechatreg(request, response, openId, wxUser.nickname,
                        wxUser.headimgurl, "", "");
                if (!map.get("result").equals(true) && !map.get("result").equals("true")) {
                    // 做失敗操作
                    logger.error("回撥地址 (登入操作,獲取使用者資訊) 返回到指定頁面==獲取使用者資訊失敗");
                }
            }
        } catch (Exception ex) {
            // 異常操作
            logger.error("回撥地址 (登入操作,獲取使用者資訊) 返回到指定頁面==獲取使用者資訊異常" + ex);
        }

        redirect(targetUrl);
        JspView view = new JspView(targetUrl);
        view.setAttribute("user", user);
        return view;
    }