JAVA 登陆这个功能我是只请求了微信的登陆,token、登陆时长等设置我仍是使用了本身项目来控制的css
微信登陆真的很坑,建议理解透了再动手开发,下面核心的地方我标注起来了前端
向APPID之类的东西,建议添加到配置里面,有不懂的能够在下面留言java
小程序登陆能够看一下个人另外一篇文章,相对来讲更简单一点 : 微信登陆-小程序版本json
话很少说,直接贴源码,复制便可用,wink~小程序
private static Logger log = LoggerFactory.getLogger(XXX.class); //调用微信接口时,增长的css样式,能够不用加,文档上有 private String href = "https://www.oschina.net/login-qrcode.css"; //回调本身项目的前端地址 private String callBackHref = "https://www.oschina.net/"; /** * @Author : Yanqiang * @Date : 2019/3/7 * @Param : [request] * @return : java.util.Map<java.lang.String,java.lang.Object> * @Description : 返回微信二维码,可供扫描登陆 * * 总体请求流程: * 登陆页面点击微信登陆 ——> 请求后端的qrconnect()接口 ——> 后端请求:https://open.weixin.qq.com/connect/qrconnect 而且传递用户扫码后微信回调项目的地址 * ——> 微信本身去判断用户有没有扫码(不须要本身写) ——> (已扫码)微信回调你请求时传递的接口 * PS: * 如下为排坑!!! * * 微信公众平台 and 微信开放平台 是不同的东西 * * 微信登陆分为 1·PC端, 2·APP, 3·小程序, 4·公众号 .... * 以上调用的地址是不一样的!!! PC端 在这个地址注册 https://open.weixin.qq.com/ 点网站应用开发,好像是注册一个三百多块钱,准备好money * 这个地址是公众号的开发!!!https://mp.weixin.qq.com/wiki 千万不要看这个去开发PC * 不一样应用之间APPID和Secret都不同(即便多个小程序或多个PC也是不一样的),一个应用一个,千万不要用错了, */ @RequestMapping(value = "qrconnect", method = RequestMethod.GET) public BaseResult qrconnect(HttpServletRequest request, HttpServletResponse response){ BaseResult baseResult = new BaseResult(); //微信二维码的接口 String wxLoginurl = "https://open.weixin.qq.com/connect/qrconnect?" + "appid={APPID}&redirect_uri={REUTL}&response_type=code&scope=snsapi_login&state={STATE}&href={HREF}#wechat_redirect"; //拼接组装扫码登陆url wxLoginurl = wxLoginurl.replace("{APPID}", "微信发放的APPID") .replace("{REUTL}","微信回调你本身项目的接口路径")//这里就是指向下面的getUserInfo()接口 .replace("{STATE}","随意填写的值,我是生成了一个随机数,也能够不变") .replace("{HREF}",href);//调用微信接口时,增长的css样式,能够不用加,文档上有 //发送请求 String result = response.encodeURL(wxLoginurl); log.info("==扫码result :"+result); // response.sendRedirect(result); //这里能够直接重定向到你的项目的前端地址, // 个人项目本身把二维码镶嵌在本身的网页中, // 没有直接跳到微信的二维码网页,因此返回地址就能够了,前端作处理 baseResult.setData(result); return baseResult; } /** * @Author : Yanqiang * @Date : 2019/3/7 * @Param : [map, request, response] * @return : java.lang.String * @Description : 微信获取用户信息,用户扫码后微信调用此接口 * 请求流程: * 获取code ——> 用code获取AccessToken ——> 用AccessToken获取userinfo * * 1·获取微信调用时传递的参数code: String code = request.getParameter("code") * 2·经过Appid,Secret,code 去获取AccessToken;接口:https://api.weixin.qq.com/sns/oauth2/access_token * 3·经过AccessToken去请求用户信息;接口:https://api.weixin.qq.com/sns/userinfo * 4·unionid: * 4.1 只有关联了小程序才有这个,没关联的只有openid * 4.2 多个应用同一用户的unionid 相同且惟一(应该相似用户在微信的惟一ID) * 5·openid: * 5.1 不一样应用之间同一用户的openid是不一样的(即便大家公司多个小程序也是不一样的) * 5.2 相同应用中同一用户openid是相同的 * 6·强烈推荐刚开始作项目就关联起来,使用unionid作用户二级ID,即便不使用unionid,也要记录起来,否则后期是个大问题 */ @RequestMapping(value = "getUserInfo", method = RequestMethod.GET) public void getUserInfo(HttpServletRequest request, HttpServletResponse response) throws IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); //从微信传递的参数里获取code String code = request.getParameter("code"); // 经过code获取WeixinOauth2Token 再获取 access_token WeixinOauth2Token oauth2Token = WeiXinUtil.getOauth2AccessToken("微信发放的APPID", "微信发放的Secret", code); log.info("===========code = "+code+"==========="); String accessToken=oauth2Token.getAccessToken(); log.info("===========accessToken = "+accessToken+"==========="); String openId=oauth2Token.getOpenId(); log.info("===========openId = "+openId+"==========="); //获取到用户的基本信息 JSONObject snsUserInfo = WeiXinUtil.getSNSUserInfo(accessToken, openId); log.info("===========snsUserInfo = "+snsUserInfo.toString()+"==========="); if(snsUserInfo!=null){ //这里能够直接拿到用户信息了,就能够你的业务处理了 String headimgurl = (String) snsUserInfo.get("headimgurl"); String nickname = (String) snsUserInfo.get("nickname"); String language = (String) snsUserInfo.get("language"); String province = (String) snsUserInfo.get("province"); String country = (String) snsUserInfo.get("country"); String unionId = (String) snsUserInfo.get("unionid"); String openid = (String) snsUserInfo.get("openid"); int sex = (Integer) snsUserInfo.get("sex"); //重定向到你的项目的前端地址 response.sendRedirect(callBackHref+"?code=1"); }else{ //获取不到用户 登陆失败 重定向到你的项目的前端地址,而且传递一个状态值 response.sendRedirect(callBackHref+"?code=0"); } }
如下为使用到的工具类后端
WeiXinUtilapi
public class WeiXinUtil { private static Logger log = LoggerFactory.getLogger(WeiXinUtil.class); //把 appid和appsecret改了就行 public final static String AccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; public final static String userinfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN"; /** * @Author : Yanqiang * @Date : 2019/3/7 * @Param : [appId, appSecret, code] * @return : com.mjt.passport.util.WeiXinUtils.WeixinOauth2Token * @Description : 网页受权认证 */ public static WeixinOauth2Token getOauth2AccessToken(String appId,String appSecret,String code) { String requestUrl=AccessTokenUrl.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE", code); //发送请求获取网页受权凭证,这个httpsRequest就不贴出来了,就是发送http请求,网上一大把,本身写也很快 JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, EnumMethod.GET.name(), null); WeixinOauth2Token wxot=new WeixinOauth2Token(); wxot.setAccessToken(jsonObject.getString("access_token")); wxot.setExpiresIn(jsonObject.getInt("expires_in")); wxot.setRefreshToken(jsonObject.getString("refresh_token")); wxot.setOpenId(jsonObject.getString("openid")); wxot.setScope(jsonObject.getString("scope")); return wxot; } /** * @Author : Yanqiang * @Date : 2019/3/7 * @Param : [accessToken, openId] * @return : com.mjt.passport.util.WeiXinUtils.SNSUserInfo * @Description : 获取用户的基本信息 打印log日志 便于查找问题 */ public static JSONObject getSNSUserInfo(String accessToken,String openId) { String requestUrl=userinfoUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId); log.info("===========requestUrl = "+requestUrl+"==========="); //经过网页受权获取用户信息 JSONObject jsonObject=CommonUtil.httpsRequest(requestUrl, EnumMethod.GET.name(), null); log.info("===========jsonObject = "+jsonObject+"==========="); return jsonObject; } }
WeixinOauth2Token微信
public class WeixinOauth2Token { //网页受权接口调用凭证 private String accessToken; //凭证有效时长 private int expiresIn; //用于刷新凭证 private String refreshToken; //用户标识 private String openId; //用户受权做用域(当scope=snsapi_base时,不弹出受权页面,直接跳转 只能获取到openId,当scope=snsapi=userinfo时弹出受权页面,获取用户信息) private String scope; public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public int getExpiresIn() { return expiresIn; } public void setExpiresIn(int expiresIn) { this.expiresIn = expiresIn; } public String getRefreshToken() { return refreshToken; } public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } 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; } }