1 OAuth是什么
OAuth是一个开放协议,允许用户让第三方应用以安全且标准的方式获取该用户在某一网站、移动或桌面应用上存储的私密的资源(如用户个人信息、照片、视频、联系人列表),而无需将用户名和密码提供给第三方应用。一般用于Web应用,桌面应用和手机以及起居室设备提供专门的认证流程中。
在我们做微信二次开发时,为了获取微信用户的信息,我们也是需要用到OAuth授权。
2 公众号后台配置
- 申请secret
- 配置授权回调页面
点击确定,域名没有设置错误的话就会提示成功了。如果没有外网域名的话,可以看看接口配置及外网映射
3 授权步骤
1. 用户授权获取code
先看看获取code的url
https://open.weixin.qq.com/connect/oauth2/authorize?
appid=APPID
&redirect_uri=REDIRECT_URI
&response_type=code
&scope=SCOPE
&state=STATE
#wechat_redirect
几个参数说明
appid:公众号的唯一标识(必填,手动填写)
redirect_uri:授权后重定向的回调链接地址(当授权成功后调转的页面)(必填,手动填写)
response_type:返回类型,请填写code(必填,固定值)
scope:应用授权作用域,
snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)(必填,手动填写)state:重定向后会带上state参数,开发者可以填写任意参数值(非必填)
#wechat_redirect
:直接在微信打开链接,可以不填此参数。做页面302重定向时候,必须带此参数(非必填)
因为我们要获取到用户的信息,所以我们在这就是用 snsapi_userinfo作用域。构造一个请求:
https://open.weixin.qq.com/connect/oauth2/authorize?
appid="你的appid"
&redirect_uri=“页面A/servlet/action”
&response_type=code
&scope=snsapi_userinfo
&state=0
#wechat_redirect
这样一个请求code的url就完成了, 只需要将这个url嵌入到公众号菜单栏上或文章链接中,用户点击就会显示授权页面了。
2. 根据code获取access_token和openid
在构造授权请求时,我们一般会将redirect_uri设置成一个servlet / action....或者是其它的后台可以接收到的请求,这样我们方便对参数code和state做处理。
我用的strut2来处理的,代码比较多,所以就贴一些关键代码吧
private final String APPID = "xxxxxxxxx";//你的appid
private final String SECRET = "xxxxxx";//你的secret
//构造获取access_token的url
private String get_access_token_url="https://api.weixin.qq.com/sns/oauth2/
access_token?" +
"appid=" +APPID+
"&secret=" +SECRET+
"&code=CODE
&grant_type=authorization_code";
发出请求后返回的的json数据:
access_token:网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
expires_in:access_token接口调用凭证超时时间,单位(秒)默认是7200s
refresh_token:用户刷新access_token
openid:用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
scope:用户授权的作用域,使用逗号(,)分隔
这样我们就获取到了用户的openid、access_token、refresh_token。access_token的过期时间为 7200s,这个时候我们就可以使用refresh_token来刷新access_token。
具体的url:
https://api.weixin.qq.com/sns/oauth2/refresh_token?
appid=APPID
&grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
返回的和刚才的json数据一样。
3 根据access_token和openid获取用户的信息
构造请求url
//构造获取用户信息的url
private String get_userinfo="https://api.weixin.qq.com/sns/userinfo?" +
"access_token=ACCESS_TOKEN&" +
"openid=OPENID&" +
"lang=zh_CN";
发出请求后返回的的json数据:
openid:用户的唯一标识
nickname:用户昵称
sex: 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
province: 用户个人资料填写的省份
city:普通用户个人资料填写的城市
country:国家,如中国为CN
headimgurl:用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege:用户特权信息,json 数组。
这样整个OAuth2认证就完成了。贴上全部代码。
Auth.class 认证action
public class Auth extends ActionSupport
private String openid;
private final String APPID = "xxxxxxxx";
private final String SECRET = "xxxxxxxx";
private String code;
private String get_access_token_url="https://api.weixin.qq.com/sns/oauth2/
access_token?" +
"appid=" +APPID+
"&secret=" +SECRET+
"&code=CODE&grant_type=authorization_code";
private String get_userinfo="https://api.weixin.qq.com/sns/userinfo?" +
"access_token=ACCESS_TOKEN&" +
"openid=OPENID&" +
"lang=zh_CN";
public String auto(){
//获取code
try {
get_access_token_url=get_access_token_url.replace("CODE", code);
//获取token and openid
String json = HttpUtil.getUrl(get_access_token_url);
JSONObject jsonObject = JSONObject.fromObject(json);
String access_token = jsonObject.getString("access_token");
openid = jsonObject.getString("openid");
//判断该用户的openid是否存在,如果不存保存该用户信息
if(!userService.openidIsExist(openid)){
//获取用户信息
get_userinfo = get_userinfo.replace("ACCESS_TOKEN", access_token);
get_userinfo = get_userinfo.replace("OPENID", openid);
String userInfoJson=HttpUtil.getUrl(get_userinfo);
JSONObject userInfoJO=JSONObject.fromObject(userInfoJson);
User userInfo = new User();
userInfo.setOpenid(userInfoJO.getString("openid"));
userInfo.setNickname(userInfoJO.getString("nickname"));
userInfo.setSex(Integer.parseInt(userInfoJO.getString("sex")));
userInfo.setProvince(userInfoJO.getString("province"));
userInfo.setHeadimgurl(userInfoJO.getString("headimgurl"));
//保存用户信息
userService.saveOrUpdate(userInfo);
}
//再查询该用户信息
user = userService.findByOpenid(openid);
} catch (NumberFormatException e) {
e.printStackTrace();
}
return "index";
}
}
HttpUtil.class
/**
* Created by Acey on 2017/1/8.
*/
public class HttpUtil {
public static String getUrl(String urlStr){
/** 网络的url地址 */
URL url = null;
/** http连接 */
HttpURLConnection httpConn = null;
/**//** 输入流 */
BufferedReader in = null;
StringBuffer sb = new StringBuffer();
try{
url = new URL(urlStr);
in = new BufferedReader( new InputStreamReader(
url.openStream(),"UTF-8") );
String str = null;
while((str = in.readLine()) != null) {
sb.append( str );
}
} catch (Exception ex) {
} finally{
try{
if(in!=null) {
in.close();
}
}catch(IOException ex) {
}
}
String result =sb.toString();
return result;
}
}
4 总结
微信内置浏览器对 localStorage的支持很差。建议使用cookie来保存数据。
防止用户从其它浏览器访问我们的网站,做了以下小小的处理。
自己想的一个比较挫的方法,大家如果有比较好的处理方法希望分享一下,第一次接触微信开发,还存在很多的问题,希望各位大牛多多指出。