微信登陆Web应用解决方案

时间: 2023-10-04 admin IT培训

微信登陆Web应用解决方案

微信登陆Web应用解决方案

1.PC端

2.移动端

3.接入流程参考微信登录Web技术接入参考


注意写入事物回滚机制(因为涉及到操作多张表避免问题,)


接入微信登陆参考代码


1.微信开放平台回调函数

/*** @param code  微信开放平台重定向这里,携带的code码* @param state 来自PC端还是Mobile端** @author simon* @date 2016/02/24*/@GET@Path("wxlogin")public void wxlogin(@QueryParam("code") String code,@QueryParam("state") String state,@Context HttpServletRequest request,@Context HttpServletResponse response) throws Exception {if (!StringUtils.isEmpty(code)) {//1.根据code请求access_tokenMap<String, Object> map = CodeUtils.get_access_token(code);String access_token = map.get("access_token").toString();String openid = map.get("openid").toString();//2.使用access_token去请求用户信息Map<String, Object> userinfoMap = CodeUtils.get_userinfo(access_token, openid);if (LuoboAppContext.currentUser() != null) {WeichatBind weichatBind = new WeichatBind();weichatBind.setUnionid(userinfoMap.get("unionid").toString());weichatBind.setUserId(LuoboAppContext.currentUser().getId());userService.createBind(weichatBind);//完成绑定if(state.equals("01")){response.sendRedirect(".html#!/user/base");//重定向到PC端页面}else{response.sendRedirect("!/user/base");//重定向到移动端页面}} else {//当前为登陆操作,去绑定表查询该微信号是否已经绑定过WeichatBind weichatBind = userService.getByUnionid(userinfoMap.get("unionid").toString());if (weichatBind != null) {//用户已经绑定过User user = userService.findById(weichatBind.getUserId());//完成模拟登陆,重定向到主页面即可autoLogin(request,response,user.getUsername(),state);} else {//用户第一次绑定,先去绑定手机号,先把userinfoMap放入session中request.getSession().setAttribute("userinfoMap", userinfoMap);//重定向到绑定手机号页面if(state.equals("01")){//来自PCresponse.sendRedirect(".html#!/bind");//去PC页面完成绑定}else{//来自移动端response.sendRedirect("!/bind");//去手机页面完成绑定}}}}}

2.后端自动登陆

/*** 后端自动登陆** @param type  PC 或 Mobile** @author simon* @date 2016/02/26* */public void autoLogin(HttpServletRequest request,HttpServletResponse response,String username,String type)throws Exception {ObjectWriter viewWriter = this.mapper.writerWithView(JsonViews.Self.class);ResponseBean rb = new ResponseBean();try {UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(username, "",userDetails.getAuthorities());//Authentication authentication = this.authManager.authenticate(authenticationToken);SecurityContextHolder.getContext().setAuthentication(authenticationToken);/** Reload user as password of authentication principal will be null after authorization and* password is needed for token generation*/
//          String ip = request.getRemoteAddr();
//          String token = TokenUtils.createToken(userDetails , ip);try {UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));LoginLog  ll        = new LoginLog();ll.setUserId(((User) userDetails).getId());ll.setIpAddress(request.getRemoteAddr());ll.setLoginTime(new Date());ll.setBrowser(userAgent.getBrowser().getName());ll.setDevice(userAgent.getOperatingSystem().getDeviceType().getName());loginLogDao.save(ll);} catch (Exception e) {logger.error("fail to save login log", e);e.printStackTrace();}//ADD TO SESSIONrequest.getSession().setAttribute(Constants.Authentication.CURRENT_USER, userDetails);List<Map> menuList = new ArrayList<Map>();if (type != null && !"".equals(type)) {User user=(User) userDetails;menuList = menuDao.findByUser(user, type);}rb.setData(MapUtils.asMap(MapUtils.any("user", userDetails), MapUtils.any("menus", menuList)));//MapUtils.any("token", token),String  userinfo   =   URLEncoder.encode(viewWriter.writeValueAsString(userDetails),   "utf-8");Cookie cookie=new Cookie("user",userinfo);cookie.setPath("/");response.addCookie(cookie);} catch (Exception e) {logger.error("faile to login", e);rb.setMessage(100001, "username or password is invalid.");}finally {rb.setData(true);response.getWriter().print(rb);//返回响应信息}}

3.读取用户的微信绑定状态

/*** 读取用户的微信绑定状态** @author simon* @date 2016/02/25*/@GET@Produces(MediaType.APPLICATION_JSON)@Path("weichatState")public ResponseBean weichatState() {ResponseBean responseBean = new ResponseBean();try{//根据当前登陆的用户id找到对应的绑定表的信息WeichatBind weichatBind = userService.getByUserId(LuoboAppContext.currentUser().getId());if(weichatBind!=null)responseBean.setData(weichatBind);elseresponseBean.setErrorCode(-1);}catch (Exception e){responseBean.setErrorCode(-1);}return responseBean;}

4.用户取消绑定微信号

/*** 用户取消绑定微信号** @author simon* @date   2016/02/25*/@GET@Produces(MediaType.APPLICATION_JSON)@Path("unbind")public ResponseBean UnBindWeixin() {ResponseBean responseBean = new ResponseBean();//根据当前登陆的用户id找到对应的绑定表的信息try {WeichatBind weichatBind = userService.getByUserId(LuoboAppContext.currentUser().getId());userService.removeBind(weichatBind.getId());}catch (Exception e){responseBean.setErrorCode(-1);}return responseBean;}

5.用户绑定手机号

/*** @描述  用户绑定手机号** @param mobileNo 绑定的手机号* @param type     PC 或 Mobile** @author simon* @date 2016/02/29*/@GET@Path("bind")public void BindWeixin(@QueryParam("mobileNo") Long mobileNo,@Context HttpServletRequest request,@Context HttpServletResponse response,@QueryParam("type") String type) throws  Exception {//1.根据要绑定的手机号信息找对应的user信息User user = userService.getUserByMobileNo(mobileNo);//2.从session获得在上一步中放入Map<String, Object> userinfoMap = (Map<String, Object>)request.getSession().getAttribute("userinfoMap");if(userinfoMap==null){ResponseBean responseBean=new ResponseBean();responseBean.setErrorCode(-2);response.getWriter().print(responseBean);//出现异常return;}if(user==null){//用户不存在,要生成账号User newuser=new User();newuser.setMobileNo(mobileNo);newuser.setName(userinfoMap.get("nickname").toString());newuser.setEnabled(true);newuser.setStatus("1");if(type.equals("PC")){newuser.setRegDevice("01");}else{newuser.setRegDevice("02");}newuser.setUsername(""+mobileNo);String password=CodeUtils.generateRandomString(6);//随机密码newuser.setPassword(this.passwordEncoder.encode(password));newuser.addRole(Constants.Role.USER);user= this.userDao.save(newuser);//生成账号//微信登陆注册成功计算获得积分try {int obtainPoints = pointsService.calculatePointsForUserRegister(user.getId());} catch (Exception e) {logger.error("error occurs: ", e);// 记录错误日志}// 注册成功的同时,新增一个对应的简历记录MicroCv cv = new MicroCv();cv.setUserId(user.getId());cv.setName(user.getName());cv.setPhone(user.getMobileNo());cv.setEmail(user.getEmail());cv.setIsSelf(true);microCvDao.save(cv);//注册成功的同时,要新增一个对应的积分记录//如果注册时带了邀请码,则给邀请人加积分
//          if (!StringUtils.isEmpty(bean.getToken())) {
//                try {
//                    pointsService.calculatePointsForInviteRegister(bean.getToken(), user.getName(), String.valueOf(user.getMobileNo()));
//                } catch (Exception e) {
//                    logger.error("error occurs: ", e);
//                    // 记录错误日志
//                }
//           }WeichatBind weichatBind = new WeichatBind();weichatBind.setUnionid(userinfoMap.get("unionid").toString());weichatBind.setUserId(user.getId());//完成绑定WeichatBind weichatBind1=userService.createBind(weichatBind);//完成模拟登陆autoLogin(request,response,user.getUsername(),type);}else{//已经存在,找到账号完成绑定,再模拟登陆WeichatBind weichatBind = new WeichatBind();weichatBind.setUnionid(userinfoMap.get("unionid").toString());weichatBind.setUserId(user.getId());WeichatBind weichatBind1=userService.createBind(weichatBind);//3.完成绑定//完成模拟登陆if(type.equals("PC")){autoLogin(request,response,user.getUsername(),"PC");}else{autoLogin(request,response,user.getUsername(),null);}}}

6.与微信平台交互的代码

package com.bigluobo.utils;import com.google.gson.*;
import com.google.gson.reflect.TypeToken;import java.io.*;
import java.*;
import java.util.*;/*** Created by Henry on 2015/12/15.*/
public class CodeUtils {private  static  final  String   appid="******************";private  static  final  String   secret="******************";//获得随机值public static final String generateRandomString(int length) {String allChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";StringBuffer sb = new StringBuffer();Random random = new Random();for (int i = 0; i < length; i++) {sb.append(allChar.charAt(random.nextInt(allChar.length())));}return sb.toString();}/*** 通过code向微信开放平台请求access_token** @param code**/public static Map<String,Object>  get_access_token(String code) {//拼接请求access_token的链接String url = "";String params="appid="+appid+"&secret="+secret+"&code="+code+"&grant_type=authorization_code";String resultJson = sendGet(url, params);Map<String,Object> map = parseData(resultJson);//将返回的json数据转换为Map结构存储/*示例:*{"access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"OPENID","scope":"SCOPE","unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"}* */return map;}/*** 函数名称: refresh_access_token** 函数描述: access_token超时,使用refresh_token重新获得一个access_token** @param   refresh_token* @return  Map<String, String>*/public static Map<String,Object> refresh_access_token(String refresh_token){//access_token超时,此时需要重新获得一个access_token。String url_access="";StringBuffer params_access=new StringBuffer().append("appid=").append(appid).append("&grant_type=refresh_token").append("&refresh_token=").append(refresh_token);String resultJson=sendGet(url_access,params_access.toString());Map<String,Object> map = parseData(resultJson);//将返回的json数据转换为Map结构存储/** {"access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"OPENID","scope":"SCOPE"}* */return map;}/*** 函数名称: get_userinfo** 函数描述: 通过access_token去获取用户的信息** @param   access_token* @return  Map<String, String>*/public static Map<String,Object> get_userinfo(String access_token,String openid){//access_token超时,此时需要重新获得一个access_token。String url_userinfo="";StringBuffer params_userinfo=new StringBuffer().append("access_token=").append(access_token).append("&openid=").append(openid);String resultJson=sendGet(url_userinfo,params_userinfo.toString());Map<String,Object> map = parseData(resultJson);//将返回的json数据转换为Map结构存储if(map.size()>3){//已经正确获取到用户信息/** {"openid":"OPENID","nickname":"NICKNAME","sex":1,"province":"PROVINCE","city":"CITY","country":"COUNTRY","headimgurl": "","privilege":["PRIVILEGE1","PRIVILEGE2"],"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"}* */return map;}else{if(map.get("errcode").equals("42001")){//access_token超时,需要重新获得access_token超时,再请求用户信息Map<String,Object> map1= refresh_access_token(access_token);String access_token2=map1.get("access_token").toString();String openid2=map1.get("openid").toString();//刷新以后重新获取用户的信息get_userinfo(access_token2,openid2);}}return map;}/*** 函数名称: parseData* 函数描述: 将json字符串转换为Map<String, String>结构** @param   data* @return  Map<String, String>*/private static Map<String, Object> parseData(String data) {GsonBuilder gb = new GsonBuilder();Gson g = gb.create();Map<String, Object> map = g.fromJson(data, new TypeToken<Map<String, Object>>() {}.getType());return map;}/*** 向指定URL发送GET方法的请求** @param url   发送请求的URL* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return URL 所代表远程资源的响应结果*/public static String sendGet(String url, String param) {String result = "";BufferedReader in = null;try {String urlNameString = url + "?" + param;URL realUrl = new URL(urlNameString);// 打开和URL之间的连接URLConnection connection = realUrl.openConnection();// 设置通用的请求属性connection.setRequestProperty("accept", "*/*");connection.setRequestProperty("connection", "Keep-Alive");connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 建立实际的连接connection.connect();// 获取所有响应头字段Map<String, List<String>> map = connection.getHeaderFields();// 定义 BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String line;while ((line = in.readLine()) != null) {result += line;}} catch (Exception e) {System.out.println("发送GET请求出现异常!" + e);e.printStackTrace();}// 使用finally块来关闭输入流finally {try {if (in != null) {in.close();}} catch (Exception e2) {e2.printStackTrace();}}return result;}
}