PC端微信扫码登录

  • Post author:
  • Post category:其他


微信扫码登录



代码解析

1.前端接口定义 restful风格 但框架并没有运用起来

前端在这里插入图片描述

2.接口实现

(1)加密参数 (随机定义)

在这里插入图片描述

(2)接口所需参数配置(微信开放平台网站应用服务申请后的appId和密钥自行配置即可)

在这里插入图片描述

(3)生成接口地址和密钥返回给前端

1.获取当前年月日字符串为密钥其中的一部分进行加密

2.字符串替换成配置类中的参数 将参数返回给前端

在这里插入图片描述

3.绑定用户微信id或者直接登录成功

(1)前端发送请求到微信开发平台 返回一张二维码 用户授权后前端会返回一个获取 AccessToken的code和我们上一个接口返回的密钥

(2)接口定义接收参数

在这里插入图片描述

code:获取AccessToken的参数

state:密钥

在这里插入图片描述

(3)接口实现

1.对密钥进行解密

2.获取AccessToken去获取微信用户信息

在这里插入图片描述

在这里插入图片描述

3.根据微信id去数据库里查询该微信id是否被绑定,如果被绑定直接返回用户信息登录成功,没有绑定的话(返回微信用户唯一id(这里返回偷了一点懒 没有定义返回对象 直接把微信id返回在里我们用户表的备注字段 这里有和前端说明))

在这里插入图片描述

(4)微信未绑定用户进行绑定

1.接口定义

在这里插入图片描述

2.参数接收

在这里插入图片描述

3.效验账号密码是否正确,然后进行绑定

在这里插入图片描述



Java代码

1.微信扫码二维码接口代码

 @ApiOperation("请求CODE(PC)")
    @PostMapping("/getWeChatQrCode/{geanre}")
    public String getWeChatQrCode(@PathVariable int geanre){
        try {
            Map<String,Object>result=usersService.getWeChatQrCode();
            return VikiClient.create(true, "获取成功",result).toString();
        }catch (Exception e){
            e.printStackTrace();
            return VikiClient.create(false, "获取失败").toString();
        }
    }

2.加密对象

public class Constanst {
    /**
     * 自定义加密措施
     */
    public static final String PWD_MD5 = "Sxz#@";
}

3.时间对象这里就不展示了 就是网上找的时间工具类

4.加密工具类

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 *
 * @author lc
 * @date 2021/5/15
 */
 
public class AESUtil {

    public static final String PASS_WORD = "9921d7d2e937422aa190794ade95c69c";
    /**
     * 加密
     *
     * @param content 需要加密的内容
     * @return
     */
    public static byte[] encrypt(String content) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom(PASS_WORD.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return result; // 加密
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**解密
     * @param content  待解密内容
     * @return
     */
    public static byte[] decrypt(byte[] content) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom(PASS_WORD.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 加密
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**将二进制转换成16进制
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**将16进制转换为二进制
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length()/2];
        for (int i = 0;i< hexStr.length()/2; i++) {
            int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
            int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
    
}

5.微信接口地址配置类(appId和secret记得输入还有回调地址定义成你们扫码登录成功后要跳转到的地址)

import java.io.Serializable;

public class HttpParame implements Serializable {
    /**
     * 应用唯一标识
     */
    public static final String APPID = "";
    /**
     * 密钥
     */
    public static final String SECRET = "";
    /**
     * 微信用户唯一标识
     */
    public static final String OPENID = "openid";
    /**
     * 接口调用凭证
     */
    public static final String ACCESS_TOKEN = "access_token";
    /**
     * 回调地址
     */
    public static final String REDIRECT_URL = "";
    /**
     * 网页授权回调地址
     */
    public static final String AUTHORIZATION_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
    /**
     * 通过code获取access_token
      */
    public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    /**
     *  此接口用于获取用户个人信息 UnionID机制
     */
    public static final String GET_UNIONID_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";

}

6.微信二维码接口实现代码

 public Map<String,Object> getWeChatQrCode() {
        String content = Constanst.PWD_MD5 + DateUtils.getNow(DateUtils.DATE_PATTERN);
        //加密
        byte[] encryptResult = AESUtil.encrypt(content);
        assert encryptResult != null;
        String encryptResultStr = AESUtil.parseByte2HexStr(encryptResult);
        String url = HttpParame.AUTHORIZATION_URL;
        url = url.replaceAll("APPID",HttpParame.APPID);
        try {
            url = url.replaceAll("REDIRECT_URI", URLEncoder.encode(HttpParame.REDIRECT_URL, "utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        url = url.replaceAll("SCOPE", "snsapi_login");
        url = url.replaceAll("STATE", encryptResultStr);
        //返回地址
        Map<String, Object> map = new HashMap<>(16);
        map.put("url", url);
        map.put("state", encryptResultStr);
        return map;
    }

7.根据微信平台扫码完成后返回的code和我们上一个接口返回的密钥state去请求微信平台的AccessToken和用户个人信息

(1)请求对象

import lombok.Data;

import java.io.Serializable;
@Data
public class WeiXinConnectRequest implements Serializable {
    private String code;
    private String state;
}

(2)接口定义(

注意

:没有生成token的业务删除代码就行)

@ApiOperation("根据code和state获取微信用户信息(PC)")
    @PostMapping("/weiXinConnect/{geanre}")
    public String weiXinConnect(@PathVariable int geanre,@RequestBody WeiXinConnectRequest request){
        try {
            AdminUsers users=usersService.weiXinConnect(request);
            //type等于0代表扫码登录成功  1代表需要绑定账号
            if (users!=null) {
                Map<String, Object> result = new HashMap<>(16);
                if (users.getId()==null) {
                    //用户未绑定账号
                    String wxId = users.getRemark();
                    //将wxId返回
                    result.put("wxId", wxId);
                    result.put("type", "1");
                    return VikiClient.create(true, "该微信还未绑定用户信息!",result).toString();
                }else{
                    //生成token 存入redis
                    String token = UUID.randomUUID().toString().replace("-", "");
                    redisTemplate.opsForValue().set(token, users, 500, TimeUnit.MINUTES);
                    result.put("token", token);
                    result.put("id", users.getId());
                    result.put("type", "0");
                    result.put("headPortrait", users.getHeadPortrait());
                }
                return VikiClient.create(true, "登陆成功",result).toString();
            }else{
                return VikiClient.create(false, "参数不能为空").toString();
            }
        }catch (RuntimeException e) {
            return VikiClient.create(false, e.getMessage(),new ArrayList<>()).toString();
        }catch (Exception e){
            e.printStackTrace();
            return VikiClient.create(false, "登陆失败").toString();
        }
    }

(3)接口实现

public AdminUsers weiXinConnect(WeiXinConnectRequest request) {
        String access_token = null;
        String openid = null;
        if (request.getCode()!=null &request.getState()!=null) {
            //解密
            byte[] decryptFrom = AESUtil.parseHexStr2Byte(request.getState());
            byte[] decryptResult =AESUtil.decrypt(decryptFrom);
            assert decryptResult != null;
            String s = new String(decryptResult);
          if (!s.equals(Constanst.PWD_MD5+DateUtils.getNow(DateUtils.DATE_PATTERN))) {
                throw new RuntimeException("登录失败!请联系管理员!");
            }
            AccessToken accessToken= this.getAccessToken(request.getCode());
            if (accessToken!=null) {
                access_token = accessToken.getAccess_token();
                openid = accessToken.getOpenid();
                if (access_token==null||openid==null) {
                    throw new RuntimeException("code已经过期请重新获取!");
                }
            }
            //获取微信用户信息
            WeiXinUserMessage weiXinUserMessage= this.getUserUnionID(access_token, openid);
            if (weiXinUserMessage!=null) {
                QueryWrapper<AdminUsers> wrapper = new QueryWrapper<>();
                wrapper.eq("wx_id", weiXinUserMessage.getOpenid());
                AdminUsers adminUsers = usersDao.selectOne(wrapper);
                if (adminUsers==null) {
                    //如果用户未绑定账号
                    AdminUsers adminUsers1 = new AdminUsers();
                    //将Openid放入对象备注字段返回
                    adminUsers1.setRemark(openid);
                    return adminUsers1;
                }else{
                    adminUsers.setHeadPortrait(weiXinUserMessage.getHeadimgurl());
                    return adminUsers;
                }
            }
        }
        return null;
    }

(4)获取AccessToken

 private AccessToken getAccessToken(String code) {
        String accessTokenUrl = HttpParame.ACCESS_TOKEN_URL;
        accessTokenUrl=accessTokenUrl.replaceAll("APPID",HttpParame.APPID);
        accessTokenUrl=accessTokenUrl.replaceAll("SECRET",HttpParame.SECRET);
        accessTokenUrl=accessTokenUrl.replaceAll("CODE",code);
        String content = null;
        try {
            content = HttpUrlConnectionUtil.get(accessTokenUrl);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (content==null||"".equals(content)) {
            return null;
        }else{
            JSONObject jsonObject = JSONObject.parseObject(content);
            return JSONObject.toJavaObject(jsonObject, AccessToken.class);
        }
    }

(5)获取微信个人信息

 private WeiXinUserMessage getUserUnionID(String access_token, String openid) {
        String unionidUrl = HttpParame.GET_UNIONID_URL;
        unionidUrl=unionidUrl.replaceAll("ACCESS_TOKEN",access_token);
        unionidUrl=unionidUrl.replaceAll("OPENID",openid);
        String content = null;
        try {
            content = HttpUrlConnectionUtil.get(unionidUrl);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (content==null||"".equals(content)) {
            return null;
        }else{
            JSONObject jsonObject = JSONObject.parseObject(content);
            return JSONObject.toJavaObject(jsonObject, WeiXinUserMessage.class);
        }
    }

8.未绑定微信id绑定用户信息

(1)请求参数

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * @author liuchang
 */
@Data
public class AppWeChatLoginRequest implements Serializable {
    @ApiModelProperty("微信id")
    private String wxId;
    @ApiModelProperty("机构简称")
    private String orgCode;
    @ApiModelProperty("登录名")
    private String loginName;
    @ApiModelProperty("登录密码")
    private String loginPwd;
}

(2)接口定义(

注意

:没有生成token的业务删除代码就行)

 @ApiOperation(value="绑定微信id(pc)")
    @PostMapping("/loginWithWeChatId/{geanre}")
    public String loginWithWeChatId(@PathVariable int geanre,@RequestBody AppWeChatLoginRequest appWeChatLoginRequest){
        try {
            _AdminUsers adminUsers = usersService.loginWithWeChatId(appWeChatLoginRequest);
            //生成token 存入redis
            String token = UUID.randomUUID().toString().replace("-", "");
            redisTemplate.opsForValue().set(token, adminUsers, 500, TimeUnit.MINUTES);
            Map<String, Object> result = new HashMap<>(16);
            result.put("token", token);
            result.put("id", adminUsers.getId());
            result.put("type", "0");
            return VikiClient.create(true, "登陆成功",result).toString();
        } catch (RuntimeException e) {
            return VikiClient.create(false, e.getMessage()).toString();
        }catch (Exception e) {
            return VikiClient.create(false, "登陆失败").toString();
        }
    }

(3)接口实现

 public _AdminUsers loginWithWeChatId(AppWeChatLoginRequest appWeChatLoginRequest) {
        //根据用户机构简称和登录名判断用户是否存在
        _AdminUsers adminUsers = adminUsersDao.selectByLoginNameAndOrgCode(appWeChatLoginRequest.getLoginName(), appWeChatLoginRequest.getOrgCode());
        if (appWeChatLoginRequest.getWxId()==null||"".equals(appWeChatLoginRequest.getWxId())) {
            throw new RuntimeException("微信id不能为空!");
        }else{
            QueryWrapper<AdminUsers> wrapper = new QueryWrapper<>();
            wrapper.eq("wx_id", appWeChatLoginRequest.getWxId());
            AdminUsers users = usersDao.selectOne(wrapper);
            if (users!=null) {
                throw new RuntimeException("该微信已经绑定过用户信息!");
            }
        }
        if (adminUsers==null) {
            throw new RuntimeException("用户登录名不存在!");
        }else{
            //效验密码是否正确
            try {
                boolean result = VikiMD5Util.validPassword(appWeChatLoginRequest.getLoginPwd(), adminUsers.getLoginPwd());
                if (result) {
                    //绑定微信id
                    if (adminUsers.getWxId()!=null&&!"".equals(adminUsers.getWxId())){
                        throw new RuntimeException("该用户已经绑定过微信无需重复绑定!");
                    }
                    adminUsers.setWxId(appWeChatLoginRequest.getWxId());
                    adminUsersDao.updateById(adminUsers);
                }else{
                    throw new RuntimeException("密码不正确,请重新输入!");
                }
            } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        adminUsers.setLoginPwd(null);
        return adminUsers;
    }

这里需要注意我们密码解密工具类自己封装的 换成自己公司的密码解密方式即可

http请求工具类

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;


public class HttpUrlConnectionUtil {

	public static String post(String urlStr,String params) throws IOException{
		URL url=new URL(urlStr);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setReadTimeout(15000);
		conn.setRequestMethod("POST");
		conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
		conn.setRequestProperty("Charset", "UTF-8");
		if(params!=null && !"".equals(params.trim())){
			conn.setDoOutput(true);
			OutputStream os=conn.getOutputStream();
			os.write(params.getBytes());
			os.flush();
			os.close();
		}
		InputStream is=conn.getInputStream();
		BufferedReader br=new BufferedReader(new InputStreamReader(is,"utf-8"));
		StringBuilder result=new StringBuilder("");
		String text=null;
		while((text=br.readLine())!=null){
			result.append(text);
		}
		if(is!=null){
			is.close();
		}
		conn.disconnect();
		return result.toString();
	}
	
	public static String post(String urlStr,String params,String cookie) throws IOException{
		URL url=new URL(urlStr);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setReadTimeout(999999999);
		if(cookie!=null && !cookie.trim().equals("")){
			conn.addRequestProperty("Cookie", cookie);
		}
		conn.setRequestMethod("POST");
		conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
		conn.setRequestProperty("Charset", "utf-8");
		if(params!=null && !"".equals(params.trim())){
			conn.setDoOutput(true);
			OutputStream os=conn.getOutputStream();
			os.write(params.getBytes());
			os.flush();
			os.close();
		}
		InputStream is=conn.getInputStream();
		BufferedReader br=new BufferedReader(new InputStreamReader(is,"gb2312"));
		StringBuilder result=new StringBuilder("");
		String text=null;
		while((text=br.readLine())!=null){
			result.append(text);
		}
		if(is!=null){
			is.close();
		}
		conn.disconnect();
		return result.toString();
	}
	
	public static String get(String urlStr) throws IOException{
		URL url=new URL(urlStr);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setReadTimeout(15000);
		conn.setRequestMethod("GET");
		conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
		conn.setRequestProperty("Charset", "UTF-8");
		InputStream is=conn.getInputStream();
		BufferedReader br=new BufferedReader(new InputStreamReader(is,"utf-8"));
		StringBuilder result=new StringBuilder("");
		String text=null;
		while((text=br.readLine())!=null){
			result.append(text);
		}
		if(is!=null){
			is.close();
		}
		conn.disconnect();
		return result.toString();
	}

	public String get(String urlStr, String cookie) throws IOException{
		Random random = new Random();
		String ip = random.nextInt(255)+"."+random.nextInt(255)+"."+random.nextInt(255)+"."+random.nextInt(255);
		URL url=new URL(urlStr);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setReadTimeout(999999999);
		conn.setRequestMethod("GET");
		conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
		conn.setRequestProperty("Charset", "utf-8");
		conn.setRequestProperty("x-forwarded-for",ip);
		if(cookie!=null && !cookie.trim().equals("")){
			conn.addRequestProperty("Cookie", cookie);
		}
		InputStream is=conn.getInputStream();
		BufferedReader br=new BufferedReader(new InputStreamReader(is,"GBK"));
		StringBuilder result=new StringBuilder("");
		String text=null;
		while((text=br.readLine())!=null){
			result.append(text);
		}
		if(is!=null){
			is.close();
		}
		conn.disconnect();
		return result.toString();
	}
}



版权声明:本文为bvgvvutvviy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。