springboot常見登錄(注冊)幾種實(shí)現(xiàn)過程
一、用戶注冊(手機(jī)驗(yàn)證碼)
目前主流采用手機(jī)號注冊方式,因?yàn)槭占绞謾C(jī)號對用戶推廣、業(yè)務(wù)推廣有極其重要的價(jià)值。結(jié)合上篇采用阿里云短信服務(wù)實(shí)現(xiàn)手機(jī)驗(yàn)證碼的發(fā)送,這里整合實(shí)現(xiàn)用手機(jī)號實(shí)現(xiàn)用戶注冊。
思路:前端在輸入手機(jī)號之后,需要對手機(jī)號進(jìn)行校驗(yàn),用戶需要接收短信驗(yàn)證碼并完成驗(yàn)證碼校驗(yàn)之后即可成功注冊。具體步驟:
- 1、判斷當(dāng)前手機(jī)號是否已注冊;
- 2、調(diào)用阿里云短信服務(wù)api實(shí)現(xiàn)驗(yàn)證碼發(fā)送;
- 3、驗(yàn)證碼發(fā)送成功并存放至redis緩存,利用緩存淘汰機(jī)制(設(shè)置有效時(shí)間)實(shí)現(xiàn)驗(yàn)證碼過期;
- 4、驗(yàn)證碼校驗(yàn),通過即注冊成功。
1.1 用戶實(shí)體類
package com.zhmsky.service_ucenter.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.util.Date;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 會員表
* </p>
*
* @author zhmsky
* @since 2022-07-16
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="UcenterMember對象", description="會員表")
public class UcenterMember implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "會員id")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
@ApiModelProperty(value = "微信openid")
private String openid;
@ApiModelProperty(value = "手機(jī)號")
private String mobile;
@ApiModelProperty(value = "密碼")
private String password;
@ApiModelProperty(value = "昵稱")
private String nickname;
@ApiModelProperty(value = "性別 1 女,2 男")
private Integer sex;
@ApiModelProperty(value = "年齡")
private Integer age;
@ApiModelProperty(value = "用戶頭像")
private String avatar;
@ApiModelProperty(value = "用戶簽名")
private String sign;
@ApiModelProperty(value = "是否禁用 1(true)已禁用, 0(false)未禁用")
private Boolean isDisabled;
@ApiModelProperty(value = "邏輯刪除 1(true)已刪除, 0(false)未刪除")
private Boolean isDeleted;
@ApiModelProperty(value = "創(chuàng)建時(shí)間")
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@ApiModelProperty(value = "更新時(shí)間")
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
}
1.2 注冊用戶視圖對象
package com.zhmsky.service_ucenter.entity.VO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author zhmsky
* @date 2022/7/16 17:18
*/
@Data
@ApiModel(value="注冊對象", description="注冊對象")
public class RegisterVO {
@ApiModelProperty(value = "昵稱")
private String nickname;
@ApiModelProperty(value = "手機(jī)號")
private String mobile;
@ApiModelProperty(value = "密碼")
private String password;
@ApiModelProperty(value = "驗(yàn)證碼")
private String code;
}
1.3 短信驗(yàn)證碼的發(fā)送
調(diào)用阿里云短信服務(wù)實(shí)現(xiàn)短信驗(yàn)證碼發(fā)送
package com.zhmsky.msmService.service.impl;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.zhmsky.msmService.service.MsmService;
import org.springframework.stereotype.Service;
/**
* @author zhmsky
* @date 2022/7/6 21:01
* 短信驗(yàn)證碼實(shí)現(xiàn)類
*/
@Service
public class MsmServiceImpl implements MsmService {
/**
* 發(fā)送短信驗(yàn)證碼
* @param phone 手機(jī)號
* @param code 被發(fā)送的驗(yàn)證碼
* @return
*/
@Override
public String sendCodeMsg(String phone, String code) {
String checkCode="";
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tDfHQPQ5WA5dBkrfFxu", "eRID7ZigveAH7fMRKbCDq92jjRl68R");
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setSignName("阿里云短信測試");
request.setTemplateCode("SMS_154950909");
request.setPhoneNumbers(phone);
request.setTemplateParam("{\"code\":\""+code+"\"}");
try {
SendSmsResponse response = client.getAcsResponse(request);
checkCode = response.getCode();
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
System.out.println("ErrCode:" + e.getErrCode());
System.out.println("ErrMsg:" + e.getErrMsg());
System.out.println("RequestId:" + e.getRequestId());
}
return checkCode;
}
}
短信驗(yàn)證碼發(fā)送接口
package com.zhmsky.msmService.controller;
import com.zhmsky.msmService.service.MsmService;
import com.zhmsky.msmService.utils.RandomUtil;
import com.zhmsky.result.Result;
import com.zhmsky.result.ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author zhmsky
* @date 2022/7/6 20:58
*/
@RestController
@Api("短信注冊控制器")
@CrossOrigin
@RequestMapping("/msmService")
public class MsmController {
@Autowired
private MsmService msmService;
@Autowired
private RedisTemplate<String,String> redisTemplate;
@GetMapping("/send/{phone}")
@ApiOperation("發(fā)送短信驗(yàn)證碼")
public Result<String> sendMsg(@PathVariable String phone){
//通過redis設(shè)置緩存時(shí)間實(shí)現(xiàn)驗(yàn)證碼過期
String code = redisTemplate.opsForValue().get(phone);
if(!StringUtils.isEmpty(code)){
return new ResultUtil<String>().setSuccessMsg("請勿重復(fù)發(fā)送!");
}
/** 如果緩存里面沒有那么就重新發(fā)送 **/
//生成隨機(jī)驗(yàn)證碼
String fourBitRandom = RandomUtil.getFourBitRandom();
//調(diào)用阿里云api實(shí)現(xiàn)短信發(fā)送
String checkCode = msmService.sendCodeMsg(phone, fourBitRandom);
if("OK".equals(checkCode)){
//將驗(yàn)證碼保存到redis中并設(shè)置有效時(shí)間為5分鐘
redisTemplate.opsForValue().set(phone,fourBitRandom,5, TimeUnit.MINUTES);
return new ResultUtil<String>().setData(fourBitRandom,"驗(yàn)證碼發(fā)送成功!");
}else{
return new ResultUtil<String>().setErrorMsg("驗(yàn)證碼發(fā)送給失敗!");
}
}
}
1.4 注冊功能實(shí)現(xiàn)
- 1、接口保護(hù),參數(shù)非空判斷;
- 2、驗(yàn)證手機(jī)號是否已注冊;
- 3、驗(yàn)證碼校驗(yàn);
- 4、入庫
/**
* 用戶注冊
* @param registerVO
* @return
*/
@Override
public boolean register(RegisterVO registerVO) {
//獲取注冊數(shù)據(jù),接口保護(hù),參數(shù)校驗(yàn)
String code = registerVO.getCode();
String mobile = registerVO.getMobile();
String nickname = registerVO.getNickname();
String password = registerVO.getPassword();
if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)||StringUtils.isEmpty(code)||StringUtils.isEmpty(nickname)){
throw new MyException(20005,"注冊失敗!");
}
//判斷手機(jī)號是否已注冊
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
Long count = baseMapper.selectCount(wrapper);
if(count>0){
throw new MyException(20005,"注冊失敗!");
}
//驗(yàn)證碼校驗(yàn)
//先從redis中獲取驗(yàn)證碼
String cacheCode = redisTemplate.opsForValue().get(mobile);
if(!code.equals(cacheCode)){
throw new MyException(20005,"注冊失敗!");
}
//入庫
UcenterMember ucenterMember = new UcenterMember();
ucenterMember.setMobile(mobile);
ucenterMember.setNickname(nickname);
ucenterMember.setPassword(MD5.encrypt(password));
ucenterMember.setIsDisabled(false);
ucenterMember.setAvatar("http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132");
int insert = baseMapper.insert(ucenterMember);
if(insert>0){
return true;
}else{
return false;
}
}
二、用戶登錄
2.1 賬號密碼登錄
登錄流程:
- 1、調(diào)用登錄接口并返回token字符串
- 2、將返回的token字符串放到cookie里面
- 3、創(chuàng)建前端攔截器,判斷cookie里面是否有token字符串,如果有則將token放到request的header中
- 4、調(diào)用接口,根據(jù)token獲取用戶信息并再次放到cookie中(為了首頁面展示)
- 5、再從cookie中取出用戶信息進(jìn)行展示
思路:
- 1、接口保護(hù),參數(shù)非空校驗(yàn);
- 2、驗(yàn)證賬號是否注冊;
- 3、驗(yàn)證賬號是否禁用;
- 4、驗(yàn)證密碼;
- 5、登錄并返回token。
為了實(shí)現(xiàn)單點(diǎn)登錄,采用token令牌方式,引入jwt
jwt工具類:
package com.zhmsky.jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author zhmsky
* @date 2022/7/6 17:53
*/
public class JwtUtils {
//設(shè)置token過期時(shí)間
public static final long EXPIRE = 1000 * 60 * 60 * 24; //一天
//簽名加密密鑰
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";
/**
* 生成token
* @param id
* @param nickname
* @return
*/
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
//設(shè)置頭信息
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//設(shè)置token過期時(shí)間
.setSubject("user") //隨便寫
.setIssuedAt(new Date())
//當(dāng)前時(shí)間加上設(shè)置的過期時(shí)間
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
//設(shè)置token主體,可存儲用戶信息
.claim("id", id)
.claim("nickname", nickname)
//簽名哈希
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
return JwtToken;
}
/**
* 判斷token是否存在與有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判斷token是否存在與有效
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根據(jù)token獲取會員id
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
登錄業(yè)務(wù):
/**
* 用戶登錄
* @param member
* @return token
*/
@Override
public String login(UcenterMember member) {
//獲取賬號和密碼
String mobile = member.getMobile();
String password = member.getPassword();
if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){
throw new MyException(20010,"賬號和密碼不能為空!");
}
//判斷賬號和密碼是否存在
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
UcenterMember ucenterMember = baseMapper.selectOne(wrapper);
if(ObjectUtils.isEmpty(ucenterMember)){
throw new MyException(20011,"賬號不存在,請重新輸入!");
}
//判斷該用戶是否被禁用
Boolean isDisabled = ucenterMember.getIsDisabled();
if(isDisabled){
throw new MyException(20013,"該賬號已禁用!");
}
//判斷密碼是否正確
//密碼存儲肯定是加密的,實(shí)際開發(fā)中數(shù)據(jù)庫不會存儲明文密碼
//先將輸入的密碼加密,再和數(shù)據(jù)庫密碼比較
//MD5加密
String realPassword = ucenterMember.getPassword();
if(!MD5.encrypt(password).equals(realPassword)){
throw new MyException(20012,"密碼錯(cuò)誤,請重新輸入!");
}
//登錄成功,返回token(通過查出來的用戶數(shù)據(jù)去生成token)
return JwtUtils.getJwtToken(ucenterMember.getId(), ucenterMember.getNickname());
}
登錄接口:
@PostMapping ("/login")
@ApiOperation("用戶登錄")
public Result<String> login(@RequestBody(required = false) UcenterMember ucenterMember){
//登錄生成token并返回
String token = memberService.login(ucenterMember);
return new ResultUtil<String>().setData(token);
}
登錄成功后,前端每次請求都攜帶token,從request對象中獲取token再解析token獲取用戶信息。
@GetMapping("/getUserInfo")
@ApiOperation("根據(jù)token獲取用戶信息")
public Result<UcenterMember> getUserInfo(HttpServletRequest httpServletRequest){
//從request對象中獲取token,再根據(jù)token獲取用戶信息
String userId = JwtUtils.getMemberIdByJwtToken(httpServletRequest);
//根據(jù)用戶id獲取用戶信息
UcenterMember ucenterMember = memberService.getById(userId);
return new ResultUtil<UcenterMember>().setData(ucenterMember);
}
2.2 微信掃碼登錄
2.2.1 準(zhǔn)備工作
網(wǎng)站應(yīng)用微信登錄是基于OAuth2.0協(xié)議標(biāo)準(zhǔn)構(gòu)建的微信OAuth2.0授權(quán)登錄系統(tǒng)。
在進(jìn)行微信OAuth2.在進(jìn)行微信OAuth2.0授權(quán)登錄接入之前,在微信開放平臺注冊開發(fā)者帳號,并擁有一個(gè)已審核通過的網(wǎng)站應(yīng)用,并獲得相應(yīng)的AppID和AppSecret,申請微信登錄且通過審核后,可開始接入流程。
2.2.2 授權(quán)流程
第三方發(fā)起微信授權(quán)登錄請求,微信用戶允許授權(quán)第三方應(yīng)用后,微信會拉起應(yīng)用或重定向到第三方網(wǎng)站,并且?guī)鲜跈?quán)臨時(shí)票據(jù)code參數(shù);
通過code參數(shù)加上AppID和AppSecret等,通過API換取access_token;
通過access_token進(jìn)行接口調(diào)用,獲取用戶基本數(shù)據(jù)資源或幫助用戶實(shí)現(xiàn)基本操作。

第一步:請求生成微信二維碼

根據(jù)官方文檔,直接請求微信開放平臺固定地址https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect,其中有4個(gè)必備的參數(shù);
appid:微信開放平臺申請通過后頒發(fā)的唯一標(biāo)識redirect_uri:微信掃碼授權(quán)后的回調(diào)地址response_type:codescope:授權(quán)作用域,web應(yīng)用直接填snsapi_login即可
準(zhǔn)備好以上參數(shù),在properties文件中完成初始值設(shè)置
wx.open.app_id=wxed9954c01bb89b47 wx.open.app_secret=a7482517235173ddb4083788de60b90e wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback
編寫參數(shù)初始化工具類:
package com.zhmsky.service_ucenter.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author zhmsky
* @date 2022/7/17 17:06
*/
@Component
public class ConstWxUtil implements InitializingBean {
@Value("${wx.open.app_id}")
private String appId;
@Value("${wx.open.app_secret}")
private String appSecret;
@Value("${wx.open.redirect_url}")
private String redirectUrl;
public static String WX_OPEN_APP_ID;
public static String WX_OPEN_APP_SECRET;
public static String WX_OPEN_REDIRECT_URL;
@Override
public void afterPropertiesSet() throws Exception {
WX_OPEN_APP_ID = appId;
WX_OPEN_APP_SECRET = appSecret;
WX_OPEN_REDIRECT_URL = redirectUrl;
}
}
二維碼生成接口:
@GetMapping("/getWxCode")
@ApiOperation("生成微信二維碼")
public String getWxCode() {
// 微信開放平臺授權(quán)baseUrl
String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
"?appid=%s" +
"&redirect_uri=%s" +
"&response_type=code" +
"&scope=snsapi_login" +
"&state=%s" +
"#wechat_redirect";
// 回調(diào)地址
String redirectUrl = ConstWxUtil.WX_OPEN_REDIRECT_URL;
try {
redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url編碼
} catch (UnsupportedEncodingException e) {
throw new MyException(20001, e.getMessage());
}
String state = "imhelen";
//生成qrcodeUrl
String qrcodeUrl = String.format(
baseUrl,
ConstWxUtil.WX_OPEN_APP_ID,
redirectUrl,
state);
return "redirect:" + qrcodeUrl;
}
第二步:微信掃碼后執(zhí)行回調(diào)
@GetMapping("/callback")
@ApiOperation("微信掃碼確認(rèn)后執(zhí)行回調(diào)")
public String callback(String code,String state){
//TODO
return "redirect:http://localhost:3000";
}
再接著

獲取隨機(jī)code,請求微信資源服務(wù)器固定地址拿到accessToken(訪問憑證)和openId(用戶唯一標(biāo)識),再通過accessToken和openId請求微信資源服務(wù)器固定地址拿到掃碼人的基本信息。獲取到用戶基本信息后就可以進(jìn)行校驗(yàn)完成入庫等操作。
@GetMapping("/callback")
@ApiOperation("微信掃碼確認(rèn)后執(zhí)行回調(diào)")
public String callback(String code,String state){
//1、接收code值
//用code去請求微信的固定地址,得到accessToken和openId
//向認(rèn)證服務(wù)器發(fā)送請求換取access_token
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
//帶參數(shù)的真實(shí)認(rèn)證服務(wù)器請求地址
String accessTokenUrl = String.format(baseAccessTokenUrl,
ConstWxUtil.WX_OPEN_APP_ID,
ConstWxUtil.WX_OPEN_APP_SECRET,
code
);
//2、請求認(rèn)證服務(wù)器獲取接口調(diào)用憑證access_token和用戶唯一標(biāo)識openId
try {
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
//將上述json字符串轉(zhuǎn)換成map對象
/*
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
*/
Gson gson = new Gson();
HashMap mapAccessTokenInfo = gson.fromJson(accessTokenInfo, HashMap.class);
//取出的access_token
String access_token = (String)mapAccessTokenInfo.get("access_token");
//取出的openid
String openid = (String)mapAccessTokenInfo.get("openid");
//3、再通過獲取出來的access_token和openid去請求微信開放平臺服務(wù)器獲取掃碼人信息
//訪問微信的資源服務(wù)器,獲取用戶信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
//發(fā)送請求獲取掃碼人基本信息
String userInfo = HttpClientUtils.get(userInfoUrl);
/*
{
"openid":"o3_SC5_eI--mIC9ikI2pvTuZhYnk",
"nickname":"Kong",
"sex":0,
"language":"",
"city":"",
"province":"",
"country":"",
"headimgurl":"https:\/\/thirdwx.qlogo.cn\/mmopen\/vi_32\/hAqkcbxzEJzic0WYl9pHDglAvYBI4iagLsSLXb2ialcxa3Au6UmwibSiadGMtbQia0oAzmzq26k2f1ES4q1HbS6aIYuA\/132",
"privilege":[],
"unionid":"oWgGz1OqVll-tTU4R_DM_zRp7Rjc"
}
*/
//將上面的json字符串轉(zhuǎn)換成map對象
HashMap mapUserInfo = gson.fromJson(userInfo, HashMap.class);
//掃碼人基礎(chǔ)信息
String nickname = (String)mapUserInfo.get("nickname");
String headImgurl=(String)mapUserInfo.get("headimgurl");
String openId=(String)mapUserInfo.get("openid");
//掃碼后自動注冊(入庫)
//先判斷是否已注冊
boolean isExist = memberService.getUserOpenId(openId);
if(!isExist){
//入庫
UcenterMember member = new UcenterMember();
member.setNickname(nickname);
member.setOpenid(openid);
member.setAvatar(headImgurl);
memberService.save(member);
}
UcenterMember ucenterMember = memberService.getUserByOpenId(openId);
String token = JwtUtils.getJwtToken(ucenterMember.getId(), ucenterMember.getNickname());
//因?yàn)槎丝谔柌煌嬖诳缬騿栴},cookie不能跨域,所以這里使用url重寫
return "redirect:http://localhost:3000?token="+token;
} catch (Exception e) {
e.printStackTrace();
throw new MyException(20010,"登錄失敗!");
}
}
總結(jié)
實(shí)現(xiàn)微信授權(quán)登錄就好比開寶箱,一共需要3把鑰匙,第一把鑰匙是appid(這個(gè)需要在微信開放平臺 完成注冊和認(rèn)證由平臺頒發(fā));
通過appid請求固定地址可以生成微信二維碼;用戶掃描二維碼授權(quán)后拿到第二把鑰匙code(隨機(jī)唯一值);
再通過code去請求固定服務(wù)器地址拿到第三把鑰匙o(hù)penid(用戶唯一標(biāo)識)和accessToken(訪問憑證);
最后再通過openid和accessToken請求固定地址拿到微信用戶基本信息。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot整合MD5加密完成注冊和登錄方式
- Springboot集成JWT實(shí)現(xiàn)登錄注冊的示例代碼
- SpringBoot結(jié)合JWT實(shí)現(xiàn)用戶登錄、注冊、鑒權(quán)
- 基于SpringBoot和Vue3的博客平臺的用戶注冊與登錄功能實(shí)現(xiàn)
- SpringBoot+JWT實(shí)現(xiàn)注冊、登錄、狀態(tài)續(xù)簽流程分析
- SpringBoot實(shí)現(xiàn)簡單的登錄注冊的項(xiàng)目實(shí)戰(zhàn)
- springboot+VUE實(shí)現(xiàn)登錄注冊
- SpringBoot實(shí)現(xiàn)登錄注冊常見問題解決方案
- SpringBoot實(shí)現(xiàn)登錄注冊的三種基本方式
相關(guān)文章
mybatis中insert返回值為1,但數(shù)據(jù)庫卻沒有數(shù)據(jù)
這篇文章主要介紹了mybatis中insert返回值為1,但數(shù)據(jù)庫卻沒有數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
基于Java實(shí)現(xiàn)OCR 文字識別的兩種方案
OCR技術(shù)已廣泛應(yīng)用于圖文轉(zhuǎn)換、證件識別、票據(jù)處理等場景,作為 Java 開發(fā)者,如何快速實(shí)現(xiàn) OCR 功能?本文將介紹兩種常用方案,幫助你快速上手 Java OCR 開發(fā),需要的朋友可以參考下2025-12-12
基于Spring AOP實(shí)現(xiàn)日志自動打印功能
這篇文章主要介紹了基于Spring AOP實(shí)現(xiàn)日志自動打印功能,文中通過代碼示例講解的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2025-01-01

