微信登陆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_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;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一缕阳光直射你的心扉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值