- 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
- 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台账号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台账号) 和 会话密钥 session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
完整代码
controller
package com.orchids.wechatlogin.web.controller;
import com.orchids.wechatlogin.web.domain.dto.UserLoginDto;
import com.orchids.wechatlogin.web.domain.exception.GlobalException;
import com.orchids.wechatlogin.web.domain.result.Result;
import com.orchids.wechatlogin.web.domain.vo.LoginVo;
import com.orchids.wechatlogin.web.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @ Author qwh
* @ Date 2024/7/19 21:14
*/
@Api(tags = "用户登录接口")
@RestController
@RequestMapping("/customer/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping("/login")
@ApiOperation("用户登录接口")
public Result<LoginVo> login(@RequestBody UserLoginDto dto) throws IOException, GlobalException {
LoginVo success = userService.login(dto);
return Result.ok(success);
}
}
service
package com.orchids.wechatlogin.web.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.orchids.wechatlogin.web.domain.dto.UserLoginDto;
import com.orchids.wechatlogin.web.domain.entity.User;
import com.orchids.wechatlogin.web.domain.exception.GlobalException;
import com.orchids.wechatlogin.web.domain.vo.LoginVo;
import java.io.IOException;
/**
* @ Author qwh
* @ Date 2024/7/19 21:13
*/
public interface UserService extends IService<User> {
LoginVo login(UserLoginDto dto) throws IOException, GlobalException;
}
package com.orchids.wechatlogin.web.service;
import com.orchids.wechatlogin.web.domain.exception.GlobalException;
import org.springframework.stereotype.Service;
import java.io.IOException;
/**
* @ Author qwh
* @ Date 2024/7/19 22:17
*/
public interface WechatService {
/**
* 获取openid
* @param code 登录凭证
* @return
* @throws IOException
*/
public String getOpenid(String code) throws IOException, GlobalException;
/**
* 获取手机号
* @param code 手机号凭证
* @return
* @throws IOException
*/
public String getPhone(String code) throws IOException;
}
serviceImpl
package com.orchids.wechatlogin.web.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orchids.wechatlogin.web.domain.constant.Constants;
import com.orchids.wechatlogin.web.domain.dto.UserLoginDto;
import com.orchids.wechatlogin.web.domain.entity.User;
import com.orchids.wechatlogin.web.domain.exception.GlobalException;
import com.orchids.wechatlogin.web.domain.vo.LoginVo;
import com.orchids.wechatlogin.web.mapper.UserMapper;
import com.orchids.wechatlogin.web.properties.JwtProperties;
import com.orchids.wechatlogin.web.service.UserService;
import com.orchids.wechatlogin.web.service.WechatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.*;
/**
* @ Author qwh
* @ Date 2024/7/19 21:16
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
private final UserMapper userMapper;
private final WechatService wechatService;
private final JwtProperties jwtProperties;
@Override
public LoginVo login(UserLoginDto dto) throws IOException, GlobalException {
//调用api获取openid
String openid = wechatService.getOpenid(dto.getCode());
//查询数据库
User user = userMapper.getUserByOpenid(openid);
//没有查到这个人
if (BeanUtil.isEmpty(user)) {
user = new User();
user.setOpenId(openid);
//获取用户手机号
String phone = wechatService.getPhone(dto.getPhoneCode());
user.setPhone(phone);
user.setName(Constants.DEFAULT_NICKNAME_PREFIX.get((int) (Math.random()* Constants.DEFAULT_NICKNAME_PREFIX.size())).toString()+ phone.substring(7));
save(user);
}
//将用户id 用户名 添加到token 返回
Map<String,Object> claims = new HashMap<>();
claims.put(Constants.JWT_USERID,user.getId());
claims.put(Constants.JWT_USERNAME,user.getName());
claims.put(Constants.EXPIRE_TIME,jwtProperties.getTtl());
String token = JWTUtil.createToken(claims, jwtProperties.getSecretKey().getBytes());
//返回前端需要的信息
LoginVo loginVo = new LoginVo();
loginVo.setToken(token);
loginVo.setNickName(user.getName());
return loginVo;
}
}
package com.orchids.wechatlogin.web.service.impl;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.orchids.wechatlogin.web.domain.constant.Constants;
import com.orchids.wechatlogin.web.domain.exception.GlobalException;
import com.orchids.wechatlogin.web.domain.exception.WechatException;
import com.orchids.wechatlogin.web.properties.WechatProperties;
import com.orchids.wechatlogin.web.service.WechatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @ Author qwh
* @ Date 2024/7/19 22:18
*/
@Service
@Slf4j
public class WechatServiceImpl implements WechatService {
@Autowired
private WechatProperties properties;
@Override
public String getOpenid(String code) {
Map<String,Object> requestParam = getAppConfig();
requestParam.put("js_code",code);
String result = HttpUtil.get(Constants.LOGIN_URL, requestParam);
JSONObject jsonObject = JSONUtil.parseObj(result);
if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))) {
throw new WechatException(jsonObject.getInt("errcode"),jsonObject.getStr("errmsg"));
}
return jsonObject.getStr("openid");
}
private Map<String, Object> getAppConfig() {
Map<String,Object> requestParam = new HashMap<>();
requestParam.put("appid",properties.getAppId());
requestParam.put("secret",properties.getAppSecret());
requestParam.put("grant_type","authorization_code");
return requestParam;
}
/**
* 获取手机号
* @return
* @throws IOException
*/
@Override
public String getPhone(String phoneCode) throws IOException {
String token = getToken();
Map<String,Object> param = new HashMap<>();
String result = HttpUtil.post(Constants.PHONE_URL+token, JSONUtil.toJsonStr(param));
JSONObject jsonObject = JSONUtil.parseObj(result);
if (jsonObject.getInt("errcode")!=0){
throw new WechatException(jsonObject.getInt("errcode"),jsonObject.getStr("errmsg"));
}
//获取手机号
// log.error("phone{}",jsonObject.getJSONObject("phone_info").getStr("purePhoneNumber"));
return jsonObject.getJSONObject("phone_info").getStr("purePhoneNumber");
}
private String getToken() {
Map<String,Object> requestParam = getAppConfig();
requestParam.put("grant_type","client_credential");
String result = HttpUtil.get(Constants.TOKEN_URL, requestParam);
JSONObject jsonObject = JSONUtil.parseObj(result);
if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))){;
throw new WechatException(jsonObject.getInt("errcode"),jsonObject.getStr("errmsg"));
}
return jsonObject.getStr("access_token");
}
}
mapper
package com.orchids.wechatlogin.web.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.orchids.wechatlogin.web.domain.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* @ Author qwh
* @ Date 2024/7/19 21:14
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select id ,phone,name,open_id,create_time,update_time from user where open_id = #{openid}")
User getUserByOpenid(String openid);
}