小程序授权登录 解密数据获取用户信息

接口文档

小程序授权登录 解密数据获取用户信息_第1张图片

pom文件

<dependency>
   <groupId>com.squareup.okhttp3</groupId>
   <artifactId>okhttp</artifactId>
   <version>3.10.0</version>
</dependency>

controller

@PostMapping("loginByCode")
    public ResultData loginByCode(@RequestBody WxLoginVo wxLoginVo){
        return ResultData.ok200().setData(wxUserService.loginByCode(wxLoginVo));
    }

service

/**
     * 微信登录
     */
    WxUser loginByCode(WxLoginVo wxLoginVo);

serviceimpl

package com.youruan.examine.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.youruan.examine.config.enums.AuthorizeEnum;
import com.youruan.examine.config.enums.CommonEnum;
import com.youruan.examine.config.excetion.ServiceException;
import com.youruan.examine.config.global.Mark;
import com.youruan.examine.entity.WxUser;
import com.youruan.examine.entity.vo.WxLoginVo;
import com.youruan.examine.entity.vo.WxUserVo;
import com.youruan.examine.mapper.WxUserMapper;
import com.youruan.examine.service.WxUserService;
import com.youruan.examine.util.HttpUtil;
import com.youruan.examine.util.WxUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Transactional
@Service
public class WxUserServiceImpl implements WxUserService {

    private Logger logger = LoggerFactory.getLogger(WxUserServiceImpl.class);

    @Autowired
    WxUserMapper userMapper;

    @Value("${examine.wxchat.appId}")
    private String appId;

    @Value("${examine.wxchat.secret}")
    private String secret;

    @Value("${examine.wxchat.grantType}")
    private String grantType;

    /**
     * 微信登录
     * @param loginVo
     * @return
     */
    @Override
    public WxUser loginByCode(WxLoginVo loginVo) {
        logger.info("loginByCode进入============="+loginVo.toString());
        WxUser resVo = new WxUser();
        if (StringUtils.isBlank(loginVo.getCode())) {
            throw new ServiceException("授权码不能为空");
        }
        WxUserVo wxUserVo = new WxUserVo();
        try {
            Map<String, Object> wxResult = getOpenIdByHttpClient(loginVo.getCode());
            logger.info(wxResult.toString());
            String sessionkey = "";
            if (wxResult.containsKey("session_key")) {
                sessionkey = wxResult.get("session_key").toString();
            }

            String openid = "";
            if (wxResult.containsKey("openid")) {
                openid = wxResult.get("openid").toString();
                logger.info(openid);
                List<WxUser> userList = listByOppenId(openid);
                /**
                 * 如果已经注册过了 直接返回数据
                 */
                if (userList.size()>0) {
                    BeanUtils.copyProperties(userList.get(0),resVo);
                    return resVo;
                }
            }
            if (StringUtils.isBlank(loginVo.getEncryptedData()) || StringUtils.isBlank(loginVo.getIv())) {
                throw new ServiceException("加密的数据不能为空");
            }
            if (StringUtils.isBlank(sessionkey)) {
                throw new ServiceException("授权信息有误");
            }
            JSONObject userInfo = WxUtil.getUserInfo(loginVo.getEncryptedData(), sessionkey, loginVo.getIv());
            logger.info(userInfo.toJSONString());
            wxUserVo = JSONObject.toJavaObject(userInfo, WxUserVo.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        loginVo.setSourceType(AuthorizeEnum.WX.getCode());
        changeUserInfo(loginVo, wxUserVo);
        //注册账号
        WxUser user = registerUserByLoginVo(loginVo);
        BeanUtils.copyProperties(user,resVo);
        return resVo;
    }
    
    
    public Map<String, Object> getOpenIdByHttpClient(String code) throws IOException {
        HttpUtil httpUtil = new HttpUtil();
        String url = Mark.WX_OPENID_URL;
        String result = httpUtil.header("X-Requested-With", "XMLHttpRequest")
                .data("appid", appId)
                .data("secret", secret)
                .data("js_code", code)
                .data("grant_type", grantType)
                .url(url)
                .get();
        Map<String, Object> map = JSONObject.parseObject(result, Map.class);
        if (!map.containsKey("openid")) {
            throw new ServiceException("错误信息:" + map.get("errmsg"));
        }
        return map;
    }

    public List<WxUser> listByOppenId(String oppenId){
        Example example = new Example(WxUser.class);
        example.createCriteria().andEqualTo("oppenId",oppenId);
        return userMapper.selectByExample(example);
    }

    private void changeUserInfo(WxLoginVo loginVo, WxUserVo userInfoVo) {
        loginVo.setUnionId(userInfoVo.getUnionId());
        loginVo.setOpenId(userInfoVo.getOpenId());
        loginVo.setAvatar(userInfoVo.getAvatarUrl());
        loginVo.setNickName(userInfoVo.getNickName());
        loginVo.setSex(userInfoVo.getGender());
    }

    /**
     * 注册(微信登录)
     *
     * @param loginVo
     * @return
     */
    private WxUser registerUserByLoginVo(WxLoginVo loginVo){
        //注册用户
        WxUser user = new WxUser();
        user.setCreateDate(new Date());
        user.setOppenId(loginVo.getOpenId());
        user.setUsername(loginVo.getNickName());
        user.setHeadImg(loginVo.getAvatar());
        user.setSex(loginVo.getSex());
        user.setUserType(CommonEnum.APPLETS.getCode());
        user.setPersonNum(UUID.randomUUID().toString().replaceAll("-", ""));
        userMapper.insertSelective(user);

        /*String codePath = "";
        try {
            codePath = createUserOrTicketCode(JSON.toJSONString(user));
        }catch (Exception e){
            throw new ServiceException("二维码生成异常");
        }
        user.setQrcode(codePath);
        userMapper.updateByPrimaryKeySelective(user);*/

        /*//绑定微信
        AuthorizeInfo info = new AuthorizeInfo();
        info.setUserId(user.getId());
        info.setSex(loginVo.getSex());
        info.setOpenType(AuthorizeEnum.WX.getCode());
        info.setOpenId(loginVo.getOpenId());
        info.setNickName(loginVo.getNickName());
        info.setAvatar(loginVo.getAvatar());
        info.setCreateTime(new Date());
        authorizeInfoMapper.insertSelective(info);*/
        return user;
    }
}

实体类 WxLoginVo

package com.youruan.examine.entity.vo;


public class WxLoginVo {

    /**
     * 授权码
     */
    private String code;

    /**
     * 加密的数据
     */
    private String encryptedData;

    /**
     * 加密偏移量
     */
    private String iv;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 头像
     */
    private String avatar;

    /**
     * 性别
     */
    private String sex;

    /**
     * 微信openId
     */
    private String openId;

    /**
     * 微信unionId
     */
    private String unionId;

    /**
     * 来源 01-微信 02-qq
     */
    private String sourceType;

    /**
     * 手机号
     */
    private String mobile;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public String getUnionId() {
        return unionId;
    }

    public void setUnionId(String unionId) {
        this.unionId = unionId;
    }

    public String getEncryptedData() {
        return encryptedData;
    }

    public void setEncryptedData(String encryptedData) {
        this.encryptedData = encryptedData;
    }

    public String getIv() {
        return iv;
    }

    public void setIv(String iv) {
        this.iv = iv;
    }

    public String getSourceType() {
        return sourceType;
    }

    public void setSourceType(String sourceType) {
        this.sourceType = sourceType;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
}

实体类 WxUserVo

package com.youruan.examine.entity.vo;


public class WxUserVo {
    /**
     * openId
     */
    private String openId;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 性别
     */
    private String gender;

    /**
     * 头像
     */
    private String avatarUrl;

    /**
     * unionId
     */
    private String unionId;

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getAvatarUrl() {
        return avatarUrl;
    }

    public void setAvatarUrl(String avatarUrl) {
        this.avatarUrl = avatarUrl;
    }

    public String getUnionId() {
        return unionId;
    }

    public void setUnionId(String unionId) {
        this.unionId = unionId;
    }
}

Util

package com.youruan.examine.util;

import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

/**
 * 说明: http请求客户端
 * @Author zhangsanfeng
 *
 * new HttpUtil().url(url)
 * .data("token", "76AF8B201FEC")
 * .data("body", json.toJSONString())
 * .post();
 *
 * new HttpUtil().url(url)
 * .data("token", "76AF8B201FEC")
 * .file("image", fileRootPath)
 * .postMultipart();
 */
public class HttpUtil {

    private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
    private final static String DEFAULT_ENCODING = "UTF-8";

    private static Logger log = LoggerFactory.getLogger(HttpUtil.class);
    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
    private static final MediaType MEDIA_TYPE_JPG = MediaType.parse("image/jpg");

    private OkHttpClient.Builder httpClient = new OkHttpClient().newBuilder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS);
    private Request.Builder requestBuilder = new Request.Builder();
    private FormBody.Builder formBodyBuilder = new FormBody.Builder();
    private MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

    private String url = "";
    private Map<String, String> headers = new LinkedHashMap<>();
    private Map<String, String> queryParas = new LinkedHashMap<>();
    private Map<String, String> files = new LinkedHashMap<>();

    public HttpUtil url(String url) {
        this.url = url;
        return this;
    }

    public HttpUtil data(String key, String value) {
        this.queryParas.put(key, value);
        return this;
    }

    public HttpUtil files(Map<String, String> files) {
        this.files.putAll(files);
        return this;
    }

    public HttpUtil file(String key, String value) {
        this.files.put(key, value);
        return this;
    }

    public HttpUtil header(String key, String value) {
        this.headers.put(key, value);
        return this;
    }

    public HttpUtil userAgent(String userAgent) {
        header("User-Agent", userAgent);
        return this;
    }

    public HttpUtil contentType(String contentType) {
        header("Content-Type", contentType);
        return this;
    }

    public HttpUtil acceptEncoding(String acceptEncoding) {
        header("Accept-Encoding", acceptEncoding);
        return this;
    }

    /**
     * Send POST request
     *
     * @throws IOException
     */
    public String post() throws IOException {
        if (StringUtils.isEmpty(url)) {
            log.error("URL为空");
            return "";
        }

        for (Entry<String, String> entry : queryParas.entrySet()) {
            formBodyBuilder.add(entry.getKey(), entry.getValue());
        }

        requestBuilder.url(url);
        for (Entry<String, String> entry : headers.entrySet()) {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }

        Request request = requestBuilder.post(formBodyBuilder.build()).build();
        Response response = httpClient.build().newCall(request).execute();

        if (!response.isSuccessful()) {
            throw new IOException("POST请求服务器端错误: " + response);
        }

        return response.body().string();
    }

    /**
     * Send GET request
     *
     * @throws IOException
     */
    public String get() throws IOException {
        if (StringUtils.isEmpty(url)) {
            log.error("URL为空");
            return "";
        }

        requestBuilder.url(buildUrlWithQueryString(url, queryParas));
        for (Entry<String, String> entry : headers.entrySet()) {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }

        Request request = requestBuilder.build();
        Response response = httpClient.build().newCall(request).execute();

        if (!response.isSuccessful()) {
            throw new IOException("GET请求服务器端错误: " + response);
        }

        return response.body().string();
    }

    /**
     * Send POST request
     *
     * @throws IOException
     */
    public String postMultipart() throws IOException {
        if (StringUtils.isEmpty(url)) {
            log.error("URL为空");
            return "";
        }

        for (Entry<String, String> entry : files.entrySet()) {
            File file = new File(entry.getValue());
            if (file.exists()) {
                multipartBodyBuilder.addFormDataPart(entry.getKey(), file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file));
            } else {
                log.warn("待上传文件没有在磁盘上找到, filePath = " + entry.getValue());
            }
        }

        for (Entry<String, String> entry : queryParas.entrySet()) {
            multipartBodyBuilder.addFormDataPart(entry.getKey(), entry.getValue());
        }

        requestBuilder.url(url);
        for (Entry<String, String> entry : headers.entrySet()) {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }

        Request request = requestBuilder.post(multipartBodyBuilder.build()).build();
        Response response = httpClient.build().newCall(request).execute();

        if (!response.isSuccessful()) {
            throw new IOException("服务器端错误: url=" + this.url + ", response=" + response.toString());
        }

        return response.body().string();
    }

    /**
     * Build queryString of the url
     */
    private static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {
        if (queryParas == null || queryParas.isEmpty()) {
            return url;
        }

        StringBuffer sb = new StringBuffer(url);
        boolean isFirst;
        if (!url.contains("?")) {
            isFirst = true;
            sb.append("?");
        } else {
            isFirst = false;
        }

        for (Entry<String, String> entry : queryParas.entrySet()) {
            if (isFirst) {
                isFirst = false;
            } else {
                sb.append("&");
            }

            String key = entry.getKey();
            String value = entry.getValue();
            if (StringUtils.isEmpty(value)) {
                try {
                    value = URLEncoder.encode(value, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
            sb.append(key).append("=").append(value);
        }
        return sb.toString();
    }

    //发送响应流方法
    public static void setResponseHeader(HttpServletResponse response, String fileName) {
        try {
            try {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public static String postData(String urlStr, String data) {
        return postData(urlStr, data, null);
    }

    public static String postData(String urlStr, String data, String contentType) {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlStr);
            URLConnection conn = url.openConnection();
            conn.setDoOutput(true);
            conn.setConnectTimeout(CONNECT_TIMEOUT);
            conn.setReadTimeout(CONNECT_TIMEOUT);
            if (contentType != null)
                conn.setRequestProperty("content-type", contentType);
            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
            if (data == null)
                data = "";
            writer.write(data);
            writer.flush();
            writer.close();

            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append("\r\n");
            }
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null)
                    reader.close();
            } catch (IOException e) {
            }
        }
        return null;
    }

}


package com.youruan.examine.util;

import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;

public class WxUtil {

    public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
        // 被加密的数据
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);

        try {
            // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return JSONObject.parseObject(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

config

package com.youruan.examine.config.excetion;

public class ServiceException extends RuntimeException {

    private static final long serialVersionUID = -250798675069124299L;
    private int errorCode;

    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public ServiceException(int errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(int errorCode, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }
}


package com.youruan.examine.config.enums;

public enum CommonEnum {

    APPLETS("01","小程序用户"),
    ORGANIZER("02","主办方");

    private String code;

    private String desc;

    CommonEnum(String code, String desc){
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

package com.youruan.examine.config.enums;

public enum AuthorizeEnum {

    WX("01","微信"),
    QQ("02","QQ");

    private String code;

    private String desc;

    AuthorizeEnum(String code, String desc){
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

Mark.java

    /**
     * 微信获取openId的url
     */
    public static final String WX_OPENID_URL = "https://api.weixin.qq.com/sns/jscode2session";

配置文件

小程序授权登录 解密数据获取用户信息_第2张图片

examine:
  wxchat:
    appId: wx
    secret: f7
    grantType: authorization_code


你可能感兴趣的:(小程序授权登录 解密数据获取用户信息)