开发前的准备:
1、需要有一个公众号(我这里用的测试号),拿到appid和appsecret;
2、进入公众号开发者中心页配置授权回调域名。具体位置:接口权限-网页服务-网页账号-网页授权获取用户基本信息-修改
注意,这里仅需填写全域名(如www.qq.com、www.baidu.com),勿加 http:// 等协议头及具体的地址字段;
我们可以通过使用ngrok来虚拟一个域名映射到本地开发环境,网址https://www.ngrok.cc/,大家自己去下载学习怎么使用
同时还需要扫一下这个二维码
授权步骤:
1、引导用户进入授权页面同意授权,获取code
2、通过code换取网页授权access_token(与基础支持中的access_token不同)
3、通过网页授权access_token和openid获取用户基本信息
先看一下我的项目结构:
web.xml相关代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<?xml version= "1.0" encoding= "utf-8" ?> <web-app xmlns:xsi= "http://www.w3.org/2001/xmlschema-instance" xmlns= "http://java.sun.com/xml/ns/javaee" xsi:schemalocation= "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id= "webapp_id" version= "3.0" > <display-name>wxauth</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file> default .html</welcome-file> <welcome-file> default .htm</welcome-file> <welcome-file> default .jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>wxcallback</servlet-name> <servlet- class >com.xingshang.servlet.callbackserclet</servlet- class > <init-param> <param-name>dburl</param-name> <param-value>jdbc:mysql: //127.0.0.1:3306/wxauth</param-value> </init-param> <init-param> <param-name>driverclassname</param-name> <param-value>com.mysql.jdbc.driver</param-value> </init-param> <init-param> <param-name>username</param-name> <param-value>root</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value> 123456 </param-value> </init-param> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>wxcallback</servlet-name> <url-pattern>/wxcallback</url-pattern> </servlet-mapping> </web-app> |
authutil工具类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package com.xingshang.util; import java.io.ioexception; import org.apache.http.httpentity; import org.apache.http.httpresponse; import org.apache.http.client.clientprotocolexception; import org.apache.http.client.methods.httpget; import org.apache.http.impl.client.defaulthttpclient; import org.apache.http.util.entityutils; import net.sf.json.jsonobject; public class authutil { public static final string appid = "wx45c1428e5584fcdb" ; public static final string appsecret = "98174450eb706ada330f37e646be85d5" ; public static jsonobject dogetjson(string url) throws clientprotocolexception, ioexception{ jsonobject jsonobject = null ; //首先初始化httpclient对象 defaulthttpclient client = new defaulthttpclient(); //通过get方式进行提交 httpget httpget = new httpget(url); //通过httpclient的execute方法进行发送请求 httpresponse response = client.execute(httpget); //从response里面拿自己想要的结果 httpentity entity = response.getentity(); if (entity != null ){ string result = entityutils.tostring(entity, "utf-8" ); jsonobject = jsonobject.fromobject(result); } //把链接释放掉 httpget.releaseconnection(); return jsonobject; } } |
java实现:
1、引导用户进入授权页面同意授权,获取code
这一步其实就是将需要授权的页面url拼接到微信的认证请求接口里面,比如需要用户在访问页面 时进行授权认证
其中的scope参数有两个值:
snsapi_base:只能获取到用户openid。好处是静默认证,无需用户手动点击认证按钮,感觉上像是直接进入网站一样。
snsapi_userinfo:可以获取到openid、昵称、头像、所在地等信息。需要用户手动点击认证按钮。
相关代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package com.xingshang.servlet; import java.io.ioexception; import java.net.urlencoder; import javax.servlet.servletexception; import javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import com.xingshang.util.authutil; /** * 入口地址 * @author administrator * */ @webservlet ( "/wxlogin" ) public class loginservlet extends httpservlet { /** * */ private static final long serialversionuid = 1l; @override protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { //第一步:引导用户进入授权页面同意授权,获取code //回调地址 // string backurl = "http://suliu.free.ngrok.cc/wxauth/callback"; //第1种情况使用 string backurl = "http://suliu.free.ngrok.cc/wxauth/wxcallback" ;//第 2 种情况使用,这里是web.xml中的路径 //授权页面地址 string url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +authutil.appid + "&redirect_uri=" +urlencoder.encode(backurl) + "&response_type=code" + "&scope=snsapi_userinfo" + "&state=state#wechat_redirect" ; //重定向到授权页面 response.sendredirect(url); } } |
2、通过第一步获取的code换取网页授权access_token(与基础支持中的access_token不同)
这一步需要在控制器中获取微信回传给我们的code,通过这个code来请求access_token,通过access_token和openid获取用户基本信息:
相关代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
package com.xingshang.servlet; import java.io.ioexception; import java.sql.connection; import java.sql.drivermanager; import java.sql.preparedstatement; import java.sql.resultset; import java.sql.sqlexception; import javax.servlet.servletconfig; import javax.servlet.servletexception; import javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import com.xingshang.util.authutil; import net.sf.json.jsonobject; /** * 回调地址 * @author administrator * */ //@webservlet("/callback") public class callbackserclet extends httpservlet { /** * */ private static final long serialversionuid = 1l; private string dburl; private string driverclassname; private string username; private string password; private connection conn = null ; private preparedstatement ps = null ; private resultset rs = null ; //初始化数据库 @override public void init(servletconfig config) throws servletexception { //加载驱动 try { this .dburl = config.getinitparameter( "dburl" ); this .driverclassname = config.getinitparameter( "driverclassname" ); this .username = config.getinitparameter( "username" ); this .password = config.getinitparameter( "password" ); class .forname(driverclassname); } catch (classnotfoundexception e) { // todo auto-generated catch block e.printstacktrace(); } } @override protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { //第二步:通过code换取网页授权access_token //从request里面获取code参数(当微信服务器访问回调地址的时候,会把code参数传递过来) string code = request.getparameter( "code" ); system.out.println( "code:" +code); //获取code后,请求以下链接获取access_token string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + authutil.appid + "&secret=" + authutil.appsecret + "&code=" + code + "&grant_type=authorization_code" ; //通过网络请求方法来请求上面这个接口 jsonobject jsonobject = authutil.dogetjson(url); system.out.println( "==========================jsonobject" +jsonobject); //从返回的json数据中取出access_token和openid,拉取用户信息时用 string token = jsonobject.getstring( "access_token" ); string openid = jsonobject.getstring( "openid" ); // 第三步:刷新access_token(如果需要) // 第四步:拉取用户信息(需scope为 snsapi_userinfo) string infourl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + token + "&openid=" + openid + "&lang=zh_cn" ; //通过网络请求方法来请求上面这个接口 jsonobject userinfo = authutil.dogetjson(infourl); system.out.println(userinfo); //第1种情况:使用微信用户信息直接登录,无需注册和绑定 // request.setattribute("info", userinfo); //直接跳转 // request.getrequestdispatcher("/index1.jsp").forward(request, response); //第2种情况: 将微信与当前系统的账号进行绑定(需将第1种情况和@webservlet("/callback")注释掉) //第一步,根据当前openid查询数据库,看是否该账号已经进行绑定 try { string nickname = getnickname(openid); if (! "" .equals(nickname)){ //已绑定 request.setattribute( "nickname" , nickname); request.getrequestdispatcher( "/index2.jsp" ).forward(request, response); } else { //未绑定 request.setattribute( "openid" , openid); request.getrequestdispatcher( "/login.jsp" ).forward(request, response); } } catch (sqlexception e) { // todo auto-generated catch block e.printstacktrace(); } } //数据库的查询 public string getnickname(string openid) throws sqlexception{ string nickname = "" ; //创建数据库链接 conn = drivermanager.getconnection(dburl, username, password); string sql = "select nickname from user where openid = ?" ; ps = conn.preparestatement(sql); ps.setstring( 1 , openid); rs = ps.executequery(); while (rs.next()) { nickname = rs.getstring( "nickname" ); } //关闭链接 rs.close(); ps.close(); conn.close(); return nickname; } //数据库的修改(openid的綁定) public int updateuser(string account,string password,string openid) throws sqlexception{ //创建数据库链接 conn = drivermanager.getconnection(dburl, username, password); string sql = "update user set openid = ? where account = ? and password = ?" ; ps = conn.preparestatement(sql); ps.setstring( 1 , openid); ps.setstring( 2 , account); ps.setstring( 3 , password); int temp = ps.executeupdate(); //关闭链接 rs.close(); ps.close(); conn.close(); return temp; } //post方法,用来接受登录请求 @override protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string account = request.getparameter( "account" ); string password = request.getparameter( "password" ); string openid = request.getparameter( "openid" ); try { int temp = updateuser(account, password, openid); if (temp > 0 ){ string nickname = getnickname(openid); request.setattribute( "nickname" , nickname); request.getrequestdispatcher( "/index2.jsp" ).forward(request, response); system.out.println( "账号绑定成功" ); } else { system.out.println( "账号绑定失败" ); } } catch (sqlexception e) { // todo auto-generated catch block e.printstacktrace(); } } } |
login.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<%@ page language= "java" contenttype= "text/html; charset=utf-8" pageencoding= "utf-8" %> <!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd" > <html> <head> <meta http-equiv= "content-type" content= "text/html; charset=utf-8" > <meta name= "viewport" content= "width=device-width,initial-scale=1.0" > <title>insert title here</title> </head> <body> <form action= "/wxauth/wxcallback" method= "post" > <input type= "text" name= "account" /> <input type= "password" name= "password" /> <input type= "hidden" name= "openid" value= "${openid }" /> <input type= "submit" value= "提交并绑定" /> </form> </body> </html> |
index.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<%@ page language= "java" contenttype= "text/html; charset=utf-8" pageencoding= "utf-8" %> <!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd" > <html> <head> <meta http-equiv= "content-type" content= "text/html; charset=utf-8" > <meta name= "viewport" content= "width=device-width,initial-scale=1.0" > <title>insert title here</title> </head> <body style= "font-size: 40px; text-align: center;" > <a href= "/wxauth/wxlogin" rel= "external nofollow" >微信公众授权登录</a> </body> </html> |
index1.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<%@ page language= "java" contenttype= "text/html; charset=utf-8" pageencoding= "utf-8" %> <!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd" > <html> <head> <meta http-equiv= "content-type" content= "text/html; charset=utf-8" > <meta name= "viewport" content= "width=device-width,initial-scale=1.0" > <title>insert title here</title> </head> <body> <div>登陆成功!</div> <div>用户昵称:${info.nickname}</div> <div>用户头像:<img style= "text-align: top;" width= "100" src= "${info.headimgurl }" ></div> </body> </html> |
index2.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<%@ page language= "java" contenttype= "text/html; charset=utf-8" pageencoding= "utf-8" %> <!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd" > <html> <head> <meta http-equiv= "content-type" content= "text/html; charset=utf-8" > <meta name= "viewport" content= "width=device-width,initial-scale=1.0" > <title>insert title here</title> </head> <body> <div>登陆成功!</div> <div>用户昵称:${nickname}</div> </body> </html> |
最后附上需要的jar包
到此,微信授权登录成功,如果有运行问题请自行调试,我这边能正常运行的
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://www.cnblogs.com/sutao/p/8727019.html