JAVA 登录这个功能我是只请求了微信的登录,token、登录时长等设置我还是使用了自己项目来控制的
微信登录真的很坑,建议理解透了再动手开发,下面核心的地方我标注起来了
向APPID之类的东西,建议添加到配置里面,有不懂的可以在下面留言
小程序登录可以看一下我的另一篇文章,相对来说更简单一点 : 微信登录-小程序版本
话不多说,直接贴源码,复制即可用,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"); } }
以下为使用到的工具类
WeiXinUtil
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; } }