[JAVA实现]微信公众号网页授权登录,java开发面试笔试题


我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。
扫描二维码或搜索下图红色VX号,加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。
推荐文章:Java 面试知识点解析Mysql优化技巧(数据库设计、命名规范、索引优化

网上搜资料时,网友都说官方文档太垃圾了不易看懂,如何如何的。现在个人整理了一个通俗易懂易上手的,希望可以帮助到刚接触微信接口的你。

请看流程图!看懂图,就懂了一半了:

其实整体流程大体只需三步:用户点击登录按钮(其实就相当于一个链接) ---》 用户点击授权登录 ----》 实现获取用户信息代码。

然后获取用户信息代码只需三步:获取code ----》 通过code获取access_token和openId ---》 通过access_token和openId获取用户信息(包含union)。

以上便是整体套路,当然官网上也有,但具体如何实现呢?

不着急,咱们一步一步来!

第一步:微信登录按钮

它其实就是一个连接,不过想得到这个链接,有一点点麻烦。

1、设置。 微信公众平台---》接口权限---》网页授权---》修改 ---》设置网页授权域名(域名,不含http://),其实就是微信调你的java方法的项目路径或项目域名,如:www.zzff.net/pp ---》点击设置后弹出页面(大致意思,将MP_verify_31qRIDcjN8ZD1lVJ.txt放在你项目路径下面,如:www.ffzz.net/pp/MP_verify_31qRIDcjN8ZD1lVJ.txt 能访问到) ---》点击确认,授权回调页面域名设置成功!

2、拼链接。 https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxx公众号IDxxxxx & redirect_uri = 授权回调页面域名/你的action(即微信授权后跳向的地址)

& response_type=code(固定的) & scope = snsapi_userinfo(或者snsapi_base默认授权) & state=STATE#wechat_redirect

如:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

这个链接中参数的具体含义,官方解释如下:

参数 是否必须 说明
appid 公众号的唯一标识
redirect_uri 授权后重定向的回调链接地址,请使用urlencode对链接进行处理
response_type 返回类型,请填写code
scope 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息
state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect 无论直接打开还是做页面302重定向时候,必须带此参数

第二步:授权确认登录

这一步最简单,第一步登录链接拼好后,在手机微信中打开,微信便会跳转到确认授权页面,点击确认授权即可。(这一步,不用开发者做处理!)

第三步:获取用户信息 (重点)
这一步便是真正的代码实现的地方。开篇便讲了,它只需三步:获取code ----》 通过code获取access_token和openId ---》 通过access_token和openId获取用户信息。

First: 获取code

Second: 获取网页授权access_token和openId

Third:通过access_token和openId获取用户信息。

关于union机制的细节:如果开发者需要公众号微信登录和APP微信登录共用一个微信ID,那个就需要union机制了。其实很简单,需在微信开放平台(open.weixin.qq.com)绑定公众号,获取用户信息时就会返回union字段

具体代码实现为:实体 ---- 方法 --- 工具

实体Oauth2Token:



 

 1 package com.wfcm.wxUitls;

 2 

 3 /**

 4 * 类名: WeixinOauth2Token </br>

 5 * 描述:  网页授权信息  </br>

 6 * 创建时间:  2015-11-27 </br>

 7 * 发布版本:V1.0  </br>

 8  */

 9 public class Oauth2Token {

10     // 网页授权接口调用凭证

11     private String accessToken;

12     // 凭证有效时长

13     private int expiresIn;

14     // 用于刷新凭证

15     private String refreshToken;

16     // 用户标识

17     private String openId;

18     // 用户授权作用域

19     private String scope;

20 

21     public String getAccessToken() {

22         return accessToken;

23     }

24 

25     public void setAccessToken(String accessToken) {

26         this.accessToken = accessToken;

27     }

28 

29     public int getExpiresIn() {

30         return expiresIn;

31     }

32 

33     public void setExpiresIn(int expiresIn) {

34         this.expiresIn = expiresIn;

35     }

36 

37     public String getRefreshToken() {

38         return refreshToken;

39     }

40 

41     public void setRefreshToken(String refreshToken) {

42         this.refreshToken = refreshToken;

43     }

44 

45     public String getOpenId() {

46         return openId;

47     }

48 

49     public void setOpenId(String openId) {

50         this.openId = openId;

51     }

52 

53     public String getScope() {

54         return scope;

55     }

56 

57     public void setScope(String scope) {

58         this.scope = scope;

59     }

60 }





View Code

实体SNSUserInfo:



 

  1 package com.wfcm.wxUitls;

  2 

  3 import java.util.List;

  4 

  5 /**

  6 * 类名: SNSUserInfo </br>

  7 * 描述: 通过网页授权获取的用户信息 </br>

  8 * 开发人员: wzf </br>

  9 * 创建时间:  2015-11-27 </br>

 10 * 发布版本:V1.0  </br>

 11  */

 12 public class SNSUserInfo {

 13     // 用户标识

 14     private String openId;

 15     // 用户昵称

 16     private String nickname;

 17     // 性别(1是男性,2是女性,0是未知)

 18     private int sex;

 19     // 国家

 20     private String country;

 21     // 省份

 22     private String province;

 23     // 城市

 24     private String city;

 25     // 用户头像链接

 26     private String headImgUrl;

 27     // 用户特权信息

 28     private List<String> privilegeList;

 29     

 30     private String unionid;

 31 

 32     public String getUnionid() {

 33         return unionid;

 34     }

 35 

 36     public void setUnionid(String unionid) {

 37         this.unionid = unionid;

 38     }

 39 

 40     public String getOpenId() {

 41         return openId;

 42     }

 43 

 44     public void setOpenId(String openId) {

 45         this.openId = openId;

 46     }

 47 

 48     public String getNickname() {

 49         return nickname;

 50     }

 51 

 52     public void setNickname(String nickname) {

 53         this.nickname = nickname;

 54     }

 55 

 56     public int getSex() {

 57         return sex;

 58     }

 59 

 60     public void setSex(int sex) {

 61         this.sex = sex;

 62     }

 63 

 64     public String getCountry() {

 65         return country;

 66     }

 67 

 68     public void setCountry(String country) {

 69         this.country = country;

 70     }

 71 

 72     public String getProvince() {

 73         return province;

 74     }

 75 

 76     public void setProvince(String province) {

 77         this.province = province;

 78     }

 79 

 80     public String getCity() {

 81         return city;

 82     }

 83 

 84     public void setCity(String city) {

 85         this.city = city;

 86     }

 87 

 88     public String getHeadImgUrl() {

 89         return headImgUrl;

 90     }

 91 

 92     public void setHeadImgUrl(String headImgUrl) {

 93         this.headImgUrl = headImgUrl;

 94     }

 95 

 96     public List<String> getPrivilegeList() {

 97         return privilegeList;

 98     }

 99 

100     public void setPrivilegeList(List<String> privilegeList) {

101         this.privilegeList = privilegeList;

102     }

103 }





View Code

方法WxController(其中authorize() 方法就是请求第一步获取的链接):



 

  1 package com.wfcm.controller;

  2 

  3 import java.io.BufferedReader;

  4 import java.io.IOException;

  5 import java.io.InputStreamReader;

  6 import java.io.UnsupportedEncodingException;

  7 import java.net.URL;

  8 import java.net.URLConnection;

  9 import java.net.URLEncoder;

 10 import java.security.MessageDigest;

 11 import java.security.NoSuchAlgorithmException;

 12 import java.util.ArrayList;

 13 import java.util.Formatter;

 14 import java.util.HashMap;

 15 import java.util.List;

 16 import java.util.Map;

 17 import java.util.UUID;

 18 

 19 import javax.servlet.http.HttpServletRequest;

 20 import javax.servlet.http.HttpServletResponse;

 21 

 22 import org.apache.http.client.utils.URLEncodedUtils;

 23 import org.json.JSONObject;

 24 import org.slf4j.Logger;

 25 import org.slf4j.LoggerFactory;

 26 import org.springframework.beans.factory.annotation.Autowired;

 27 import org.springframework.stereotype.Controller;

 28 import org.springframework.web.bind.annotation.RequestMapping;

 29 import org.springframework.web.bind.annotation.ResponseBody;

 30 

 31 import com.alibaba.fastjson.JSON;

 32 import com.alibaba.fastjson.JSONArray;

 33 import com.alibaba.fastjson.util.IOUtils;

 34 import com.wfcm.annotation.IgnoreSign;

 35 import com.wfcm.annotation.IgnoreToken;

 36 import com.wfcm.entity.WfMemberEntity;

 37 import com.wfcm.service.WfMemberService;

 38 import com.wfcm.service.WfMemberSessionService;

 39 import com.wfcm.utils.FastJSONUtils;

 40 import com.wfcm.utils.NetUtil;

 41 import com.wfcm.utils.R;

 42 import com.wfcm.wxUitls.AccessToken;

 43 import com.wfcm.wxUitls.JsapiTicket;

 44 import com.wfcm.wxUitls.Oauth2Token;

 45 import com.wfcm.wxUitls.SNSUserInfo;

 46 

 47 @Controller

 48 @RequestMapping("/wx")

 49 @ResponseBody

 50 public class WxController {

 51 

 52     private static  Logger log = LoggerFactory.getLogger(WxController.class);

 53      

 54     

 55     /**

 56      * 向指定URL发送GET方法的请求

 57      * 

 58      * @param url

 59      *            发送请求的URL

 60      * @param param

 61      *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。

 62      * @return URL 所代表远程资源的响应结果

 63      * 

 64      * 用户同意授权,获取code

 65      */ 

 66     @RequestMapping("/authorize")

 67     @ResponseBody

 68     @IgnoreToken

 69     public static R authorize() {

 70         String appid = "wxbb000000000e";

 71         //String uri ="wftest.zzff.net/wx/weixinLogin"; 

 72         String uri = urlEncodeUTF8("wftest.zzff.net/api/wx/weixinLogin");

 73         String result = "";

 74         BufferedReader in = null;

 75         try {

 76             String urlNameString = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appid+"&redirect_uri="+uri+"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

 77             

 78             URL realUrl = new URL(urlNameString);

 79             // 打开和URL之间的连接

 80             URLConnection connection = realUrl.openConnection();

 81             // 设置通用的请求属性

 82             connection.setRequestProperty("accept", "*/*");

 83             connection.setRequestProperty("connection", "Keep-Alive");

 84             connection.setRequestProperty("user-agent",

 85                     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

 86             // 建立实际的连接

 87             connection.connect();

 88             // 获取所有响应头字段

 89             Map<String, List<String>> map = connection.getHeaderFields();

 90             // 遍历所有的响应头字段

 91             for (String key : map.keySet()) {

 92                 System.out.println(key + "--->" + map.get(key));

 93             }

 94             // 定义 BufferedReader输入流来读取URL的响应

 95             in = new BufferedReader(new InputStreamReader(

 96                     connection.getInputStream()));

 97             String line =null;

 98             while ((line = in.readLine()) != null) {

 99                 result += line;

100             }

101             /*  com.alibaba.fastjson.JSONObject jsonObj= FastJSONUtils.getJSONObject(result);  

102                 String access_token = jsonObj.getString("access_token");

103                 long expires_in = Long.valueOf(jsonObj.getString("expires_in"));

104             */

105         } catch (Exception e) {

106             System.out.println("发送GET请求出现异常!" + e);

107             e.printStackTrace();

108         }

109         // 使用finally块来关闭输入流

110         finally {

111             try {

112                 if (in != null) {

113                     in.close();

114                 }

115             } catch (Exception e2) {

116                 e2.printStackTrace();

117             }

118         }

119         return  R.ok(result);

120     }    

121     

122     @RequestMapping("/weixinLogin")

123     @ResponseBody

124     @IgnoreToken

125     @IgnoreSign

126     public void weixinLogin(HttpServletRequest request,HttpServletResponse response) throws Exception {  

127         // 用户同意授权后,能获取到code

128         Map<String, String[]> params = request.getParameterMap();//针对get获取get参数  

129         String[] codes = params.get("code");//拿到code的值 

130         String code = codes[0];//code  

131         //String[] states = params.get("state");

132         //String state = states[0];//state 

133         

134         System.out.println("****************code:"+code);          

135         // 用户同意授权

136         if (!"authdeny".equals(code)) {

137              // 获取网页授权access_token

138             Oauth2Token oauth2Token = getOauth2AccessToken("wxb0000000000e", "4c22222233333335555a9", code);

139             System.out.println("***********************************oauth2Token信息:"+oauth2Token.toString());

140             // 网页授权接口访问凭证

141             String accessToken = oauth2Token.getAccessToken();

142             // 用户标识

143             String openId = oauth2Token.getOpenId();

144             // 获取用户信息

145             SNSUserInfo snsUserInfo = getSNSUserInfo(accessToken, openId);

146             System.out.println("***********************************用户信息unionId:"+snsUserInfo.getUnionid()+"***:"+snsUserInfo.getNickname());

147             // 设置要传递的参数

148             

149             //具体业务start

150 

151            //具体业务end

152 

153             String url = "http://wftest.zzff.net/#/biddd?from=login&tokenId="+snsUserInfo.getUnionid();

154             

155             response.sendRedirect(url); 

156             return ;

157         }

158     }  

159 

160     

161     /**

162      * 获取网页授权凭证

163      * 

164      * @param appId 公众账号的唯一标识

165      * @param appSecret 公众账号的密钥

166      * @param code

167      * @return WeixinAouth2Token

168      */

169     public static Oauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {

170         Oauth2Token wat = null;

171         // 拼接请求地址

172         String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

173         requestUrl = requestUrl.replace("APPID", appId);

174         requestUrl = requestUrl.replace("SECRET", appSecret);

175         requestUrl = requestUrl.replace("CODE", code);

176         // 获取网页授权凭证

177         com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(NetUtil.get(requestUrl));

178         if (null != jsonObject) {

179             try {

180                 wat = new Oauth2Token();

181                 wat.setAccessToken(jsonObject.getString("access_token"));

182                 wat.setExpiresIn(jsonObject.getInteger("expires_in"));

183                 wat.setRefreshToken(jsonObject.getString("refresh_token"));

184                 wat.setOpenId(jsonObject.getString("openid"));

185                 wat.setScope(jsonObject.getString("scope"));

186             } catch (Exception e) {

187                 wat = null;

188                 int errorCode = jsonObject.getInteger("errcode");

189                 String errorMsg = jsonObject.getString("errmsg");

190                 log.error("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode, errorMsg);

191             }

192         }

193         return wat;

194     }

195     

196     /**

197      * 通过网页授权获取用户信息

198      * 

199      * @param accessToken 网页授权接口调用凭证

200      * @param openId 用户标识

201      * @return SNSUserInfo

202      */

203     public static SNSUserInfo getSNSUserInfo(String accessToken, String openId) {

204         SNSUserInfo snsUserInfo = null;

205         // 拼接请求地址

206         String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";

207         requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);

208         // 通过网页授权获取用户信息

209         com.alibaba.fastjson.JSONObject jsonObject =  JSON.parseObject(NetUtil.get(requestUrl));

210 

211         if (null != jsonObject) {

212             try {

213                 snsUserInfo = new SNSUserInfo();

214                 // 用户的标识

215                 snsUserInfo.setOpenId(jsonObject.getString("openid"));

216                 // 昵称

217                 snsUserInfo.setNickname(jsonObject.getString("nickname"));

218                 // 性别(1是男性,2是女性,0是未知)

219                 snsUserInfo.setSex(jsonObject.getInteger("sex"));

220                 // 用户所在国家

221                 snsUserInfo.setCountry(jsonObject.getString("country"));

222                 // 用户所在省份

223                 snsUserInfo.setProvince(jsonObject.getString("province"));

224                 // 用户所在城市

225                 snsUserInfo.setCity(jsonObject.getString("city"));

226                 // 用户头像

227                 snsUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));

228                 // 用户特权信息

229                 List<String> list = JSON.parseArray(jsonObject.getString("privilege"),String.class);

230                 snsUserInfo.setPrivilegeList(list);

231                 //与开放平台共用的唯一标识,只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。

232                 snsUserInfo.setUnionid(jsonObject.getString("unionid"));

233             } catch (Exception e) {

234                 snsUserInfo = null;

235                 int errorCode = jsonObject.getInteger("errcode");

236                 String errorMsg = jsonObject.getString("errmsg");

237                 log.error("获取用户信息失败 errcode:{} errmsg:{}", errorCode, errorMsg);

238             }

239         }

240         return snsUserInfo;

241     }

242    

243     /**

244      * URL编码(utf-8)

245      * 

246      * @param source

247      * @return

248      */

249     public static String urlEncodeUTF8(String source) {

250         String result = source;

251         try {

252             result = java.net.URLEncoder.encode(source, "utf-8");

253         } catch (UnsupportedEncodingException e) {

254             e.printStackTrace();

255         }

256         return result;

257     }

258     

259     private static String byteToHex(final byte[] hash) {

260         Formatter formatter = new Formatter();

261         for (byte b : hash)

262         {

263             formatter.format("%02x", b);

264         }

265         String result = formatter.toString();

266         formatter.close();

267         return result;

268     }

269 

270     private static String create_nonce_str() {

271         return UUID.randomUUID().toString();

272     }

273 

274     private static String create_timestamp() {

275         return Long.toString(System.currentTimeMillis() / 1000);

276     }

277 }





View Code

工具NetUtil:



 

 1 package com.wfcm.utils;

 2 

 3 import java.io.BufferedInputStream;

 4 import java.io.IOException;

 5 import java.io.InputStreamReader;

 6 import java.io.UnsupportedEncodingException;

 7 import java.util.ArrayList;

 8 import java.util.Collection;

 9 import java.util.List;

10 import java.util.Map;

11 

12 import org.apache.commons.httpclient.NameValuePair;

13 import org.apache.http.HttpEntity;

14 import org.apache.http.HttpResponse;

15 import org.apache.http.client.entity.UrlEncodedFormEntity;

16 import org.apache.http.client.methods.HttpGet;

17 import org.apache.http.client.methods.HttpPost;

18 import org.apache.http.impl.client.CloseableHttpClient;

19 import org.apache.http.impl.client.HttpClientBuilder;

20 import org.apache.http.message.BasicNameValuePair;

21 

22 /**

23  * Created by Song on 2016/11/28.

24  * 基于HttpClient提供网络访问工具

25  */

26 public final class NetUtil {

27     public static CloseableHttpClient httpClient = HttpClientBuilder.create().build();

28 

29     /**

30      * get请求获取String类型数据

31      * @param url 请求链接

32      * @return

33      */

34     public static String get(String url){

35         StringBuffer sb = new StringBuffer();

36         HttpGet httpGet = new HttpGet(url);

37         try {

38             HttpResponse response = httpClient.execute(httpGet);           //1

39 

40             HttpEntity entity = response.getEntity();

41             InputStreamReader reader = new InputStreamReader(entity.getContent(),"utf-8");

42             char [] charbufer;

43             while (0<reader.read(charbufer=new char[10])){

44                 sb.append(charbufer);

45             }

46         }catch (IOException e){//1

47             e.printStackTrace();

48         }finally {

49             httpGet.releaseConnection();

50         }

51         return sb.toString();

52     }

53 

54     /**

55      * post方式请求数据

56      * @param url 请求链接

57      * @param data post数据体

58      * @return

59      */

60     @SuppressWarnings("unchecked")

61     public static String post(String url, Map<String,String> data){

62         StringBuffer sb = new StringBuffer();

63         HttpPost httpPost = new HttpPost(url);

64         List<NameValuePair> valuePairs = new ArrayList<NameValuePair>();

65         if(null != data) {

66             for (String key : data.keySet()) {

67                 valuePairs.addAll((Collection<? extends NameValuePair>) new BasicNameValuePair(key, data.get(key)));

68             }

69         }

70         try {

71             httpPost.setEntity(new UrlEncodedFormEntity((List<? extends org.apache.http.NameValuePair>) valuePairs));

72             HttpResponse response = httpClient.execute(httpPost);

73             HttpEntity httpEntity = response.getEntity();

74             BufferedInputStream bis = new BufferedInputStream(httpEntity.getContent());

75             byte [] buffer;

76             while (0<bis.read(buffer=new byte[128])){

77                 sb.append(new String(buffer,"utf-8"));

78             }

79         }catch (UnsupportedEncodingException e){//数据格式有误

80             e.printStackTrace();

81         }catch (IOException e){//请求出错

82             e.printStackTrace();

83         }finally {

84             httpPost.releaseConnection();

85         }

86         return sb.toString();

87     }

88     

89     

90  }





View Code

R类:



 

package com.wfcm.utils;

import java.util.HashMap;

import java.util.Map;

/**

 * 返回数据

 * 

 * @author xlf

 * @email [email protected]

 * @date 2017年4月19日 上午11:58:56

 */

public class R extends HashMap<String, Object> {

    private static final long serialVersionUID = 1L;

    public static final String SUCCESS = "success";

    

    public static final String EXCEPTION = "exception";

    

    public static final Integer SUCCESSCODE = 0;

        

    public static final Integer EXCEPTIONCODE = 500;

    

    public R() {

        put("errCode", 0);

        put("msg", SUCCESS);

    }

    

    public R(int code, String msg){

           put("errCode", code);

            put("msg", msg);

    }

    public static R error() {

        return error(500, "未知异常,请联系管理员");

    }

    public static R error(String msg) {

        return error(500, msg);

    }

    public static R error(int code, String msg) {

        R r = new R();

        r.put("errCode", code);

        r.put("msg", msg);

        return r;

    }

    public static R ok(String msg) {

        R r = new R();

        r.put("msg", msg);

        return r;

    }

    public static R ok(Map<String, Object> map) {

        R r = new R();

        r.putAll(map);

        return r;

    }

    public static R ok() {

        return new R();

    }

    public R put(String key, Object value) {

        super.put(key, value);

        return this;

    }

}





View Code

OK,大功告成!整体流程已经搭建起来,读懂了这些代码差不多就明白了整个流程了,然后再看官方文档,你会觉得读起来很顺畅,而不是刚开始那种味同嚼蜡的感觉。你只需再根据官方文档仔细检查检查流程,有没有需要完善的地方,就可以了。

还等什么呢,赶快敲实现功能吧!!!


转载:https://www.cnblogs.com/hero123/p/9010506.html

推荐内容:
java的@PostConstruct注解
转:Java后端面试自我学习
java加载properties文件的几种方式
java 一次CPU占用过高问题的排查及解决
java后台导出excel代码详细讲解
Java方向如何准备BAT技术面试答案(汇总版)
两道面试题,带你解析Java类加载机制
2018 java BAT最新面试宝典
JAVA日志的前世今生
Java并发之线程池ThreadPoolExecutor源码分析学习

猜你喜欢

转载自blog.csdn.net/agoodcoder777/article/details/89630307