springmvc实现微信扫码登陆网站功能
程序员文章站
2024-01-24 18:22:34
...
微信扫码登陆过程
- 在微信开放平台上注册并创建网站应用,等待审核;需提供公司章及域名等信息
- 审核通过后获取AppID和AppSecret
- 思考流程:
- 首先思考如何生成二维码
- 扫码后的情况
- 用户未绑定网站时,跳转到绑定界面
- 用户绑定过网站,扫码后直接登陆并跳转到首页
- 用户绑定账号的问题:
- 该账号已绑定过,需要提示
- 该微信已绑定过(不需要想了,扫码直接登陆了,不会跳转到绑定界面)
- 用户解绑:
- 在个人中心添加对微信绑定的管理,解绑就是将微信获取到的unionid置空即可。
- 编码思路:
注意:开放平台只有绑定公众号才可以获取到unionid,这里使用的是unionid,如果没有则用openid。
3.1 生成二维码
@GetMapping("wechat")
public void Wechat(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String url = "https://open.weixin.qq.com/connect/qrconnect?appid=" + WeixinUtil.KAPPID
+ "&redirect_uri=" + URLEncoder.encode(WeixinUtil.CORE_REDIRECT_URL)
+ "&response_type=code"
+ "&scope=snsapi_login&state=STATE#wechat_redirect";//返回需要扫码的二维码html
resp.sendRedirect(url);
}
WeixinUtil.KAPPID:公众平台获取的appid
WeixinUtil.CORE_REDIRECT_URL:扫码后需要跳转到处理的回调方法,这里是http://域名/项目名/路由/callBack
3.2 扫码后处理的回调
//扫码后回调
@RequestMapping(value = "/callBack")
@ResponseBody
protected ModelAndView callBack(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String code = req.getParameter("code");
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + WeixinUtil.KAPPID
+ "&secret=" + WeixinUtil.KAPPSECRET
+ "&code=" + code
+ "&grant_type=authorization_code";
net.sf.json.JSONObject jsonObject = AuthUtil.doGetJson(url);
String openid = jsonObject.getString("openid");
String token = jsonObject.getString("access_token");
String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + token
+ "&openid=" + openid
+ "&lang=zh_CN";
JSONObject userInfo = AuthUtil.doGetJson(infoUrl);
//1.使用微信用户信息直接登录,无需注册和绑定
System.out.println(userInfo);
//当前开放平台与公众号绑定,可以获取到用户unionid,否则获取不到。
String unionid = userInfo.getString("unionid");
//2.将微信与当前系统的账号进行绑定
List<User> listLogin = userService.findByOpenid(unionid);//查询当前unionid是否被绑定过
System.out.println("listLogin==" + listLogin);
if (listLogin.size() > 0) {
//已经存在直接登陆,跳转到首页,此处是shiro登陆代码,可更换为自己的默认登陆形式
Subject user = SecurityUtils.getSubject();
String name = listLogin.get(0).getName();
VXToken usertoken = new VXToken(name, listLogin.get(0).getP_password(), name);
usertoken.setRememberMe(false);
try {
user.login(usertoken);
} catch (Exception e) {
throw new RuntimeException("账号登陆异常!请联系管理员", e);
}
System.out.println("openid--------------------------------" + openid);
System.out.println("unionid------------------------------" + unionid);
req.getRequestDispatcher("/home").forward(req, resp);
return null;
} else {
//不存在跳转到绑定页面
System.out.println("openid--------------------------------" + openid);
System.out.println("unionid------------------------------" + unionid);
//跳转到账号绑定页面,并将unionid传给页面
return new ModelAndView("/portals/account/accountbind", "openid", unionid);
}
}
WeixinUtil.KAPPSECRET:开放平台获取的 appsecret
3.3 绑定页面及绑定方法
//绑定页面加载,绑定页面需要输入用户名及密码来验证身份
@GetMapping("accountbind")
public String accountBind(Model model, String unionid) {
model.addAttribute("openid", unionid);
return "/portals/account/accountbind";
}
//绑定方法
@PostMapping("bind")
@ResponseBody
public Object bind(String username, String password, String unionid) {
Subject user = SecurityUtils.getSubject();
UserNameToken token = new UserNameToken(username, password, username);
token.setRememberMe(false);
try {
//根据用户输入的用户名密码进行登陆,登陆不成功则验证失败,成功后再进行微信绑定 user.login(token);
UserVo uservo = new UserVo();
uservo.setName(username);
uservo.setP_email(username);
List<User> listLogin = userService.selectByLoginName(uservo);
System.out.println("listLogin==" + listLogin);
Long id = listLogin.get(0).getId();
String open_id = listLogin.get(0).getOpen_id();
//判断openid是否为空,
//为空则表示没有绑定,将openid插入到当前登陆用户的表中
//不为空则表示已经被绑定过,不可以再次绑定
if (open_id == "" || open_id == null) {
userService.bindOpenId(id, unionid);//绑定openid
} else {
return renderError("该账号已绑定!");
}
} catch (UnknownAccountException e) {
throw new RuntimeException("账号不存在!", e);
} catch (DisabledAccountException e) {
throw new RuntimeException("账号未启用!", e);
} catch (IncorrectCredentialsException e) {
throw new RuntimeException("密码错误!", e);
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(), e);
}
return renderSuccess();
}
参考:https://blog.csdn.net/qq_37361830/article/details/80415947
https://blog.csdn.net/weixin_41981080/article/details/81869592