微信登陆Web应用解决方案

来源:互联网 发布:淘宝等级最高的买家 编辑:程序博客网 时间:2024/04/28 04:11

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_token            Map<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("http://www.jkgst.com/main.html#!/user/base");//重定向到PC端页面                }else{                    response.sendRedirect("http://www.jkgst.com/m/#!/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")){                        //来自PC                        response.sendRedirect("http://www.jkgst.com/main.html#!/bind");//去PC页面完成绑定                    }else{                        //来自移动端                        response.sendRedirect("http://www.jkgst.com/m/#!/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 SESSION            request.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);            else                responseBean.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.net.*;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 = "https://api.weixin.qq.com/sns/oauth2/access_token";        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="https://api.weixin.qq.com/sns/oauth2/refresh_token";        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="https://api.weixin.qq.com/sns/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": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",                "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;    }}
0 0