关闭

微信登陆Web应用解决方案

标签: 微信解决方案web应用技术移动
9819人阅读 评论(0) 收藏 举报
分类:

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;
    }
}
1
0
查看评论

网页微信登录原理

这两天一直在看网页版的微信,对网页微信登录原理进行了思考。网页版微信地址:https://wx.qq.com/ 网页微信登录方法: 1.打开网页版微信地址,会看到一个二维码。 2.打开手机微信客户端,再点击界面上的如下按钮: 3.扫面二维码,手机客户端会提示是否登...
  • killer000777
  • killer000777
  • 2013-06-27 16:12
  • 9793

微信(移动端web)开发中的一些坑与心得

最初接触微信开发的时候 应该是快两年前   那个时候 微信开发只能做一些简单(基础)的事情  比如自定义内容回复,获取用户位置信息等   而且更重要的是  WeixinJs接口 内容太少  所以没玩多久 就没有继续开发微信了  直到前一段时...
  • CallMeJason
  • CallMeJason
  • 2016-01-06 11:19
  • 2711

【微信第三方登录】 解决PC和移动端浏览器同为扫码登录

点击打开链接
  • Smile___you
  • Smile___you
  • 2016-12-01 09:36
  • 3732

微信调用jssdk在网页端实现调用扫一扫,java+jsp

这篇文章以讲解的方式,帮助大家来理解微信官方的文档,同时给出调用扫一扫的例子。 微信官方技术文档jssdk:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html 打开技术文档,看到一个大目录,我们只需要关注下面几部分...
  • u011327333
  • u011327333
  • 2015-12-31 10:09
  • 26934

使用java进行web微信登录模拟

好久没有写博客了,上一篇博客模拟登录smartqq浏览量达到了2000+,也许大家对这些很猎奇吧,鉴于很多原因,之前smartqq将百度云链接给关闭了,至于原因,是因为核心代码已经给出了,拒绝伸手党,也是促进爬虫事业进步的一大原则性问题。好了,废话不多说,上代码! 本博客禁止其他网站采集发布,...
  • qq_19383667
  • qq_19383667
  • 2017-06-03 23:33
  • 2919

微信网页第三方登录原理

转自 http://www.cnblogs.com/examine/p/4634947.html 微信开放平台和公众平台的区别 1.公众平台面向的时普通的用户,比如自媒体和媒体,企业官方微信公众账号运营人员使用,当然你所在的团队或者公司有实力去开发一些内容,也可以调用公众平台里面的...
  • skykingf
  • skykingf
  • 2016-06-20 16:32
  • 5788

微信第三方登录与静默授权

微信的授权登录在日常应用中应用的非常广泛,最多就是第三方登录,最近在搞这方面的例子,做个笔记,方便查阅。 微信登录分为两类:需要用户确认的授权登录与静默授权,用户确认的授权登录因为要通过用户的个人确认,所以可以获取用户全面的信息,无论是否关注相关微信号都可以获取,静默授权是嵌套在普通网页中的授权方式...
  • u013407099
  • u013407099
  • 2016-10-20 10:50
  • 26482

微信web开发工具-授权登录

释: 我是订阅号,申请的微信开发测试账号,操作授权登录 1.  下载web开发工具 2.  在公众号列表中, 开发者工具-》web开发工具-> 绑定开发者账号 -》输入你的微信号(微信号需关注公众号才可绑定),邀请绑定在微信客户端确认邀请即可 ...
  • xiaoyezihanghui
  • xiaoyezihanghui
  • 2016-10-27 16:45
  • 1483

WebApp微信集成登录

把一个WebApp发布在微信公众号上,并且想使用微信用户的信息,以求达到微信集成登录的目的。官方文档讲的也很详细,然而在做的过程中还是遇到很多坑,分享出来希望能对有需要的人有所帮助。实现效果如下: 微信浏览器授权的前提:  1.拥有微信公众号,即有APPID,APPSecret...
  • Admin_yi
  • Admin_yi
  • 2017-02-24 17:12
  • 2461

HBuilder webApp开发(八)微信/QQ/新浪登录

接着昨天的《HTML5 WebApp开发(七)微信/QQ/新浪分享》 继续写了一下第三方登录。 首先是去官方文档和Demo找,发现官方文档基本就是那些配置的说明,但是Demo就需要去github上面查看-传送门 还好官方有Demo,不然真的不知道怎么下手。 在写代码之前,首先是查看文档和De...
  • zhuming3834
  • zhuming3834
  • 2016-06-19 10:54
  • 9593
    个人资料
    • 访问:296407次
    • 积分:4219
    • 等级:
    • 排名:第8603名
    • 原创:148篇
    • 转载:8篇
    • 译文:0篇
    • 评论:56条
    博客专栏