Sprigboot项目中实现微信小程序登录案例
·
接入微信登录可以通过微信开放平台的授权登录功能实现,如何实现微信小程序使用微信登录案例
- 注册微信开放平台账号并创建应用:
首先注册微信开放平台账号,并在开发者中心创建一个应用,获取到AppID和AppSecret。
- 配置Spring Boot项目:
在application.properties或application.yml中配置微信登录的相关信息:
wechat.appId=your_app_id
wechat.appSecret=your_app_secret
wechat.redirectUrl=http://localhost:8080/login/wechat/callback
- 创建微信登录控制器:
-
@PostMapping("/weixin-mini-app-login") @Operation(summary = "微信小程序的一键登录") @PermitAll public CommonResult<AppAuthLoginRespVO> weixinMiniAppLogin(@RequestBody @Valid AppAuthWeixinMiniAppLoginReqVO reqVO) { return success(authService.weixinMiniAppLogin(reqVO)); }@Schema(description = "用户 APP - 微信小程序手机登录 Request VO") @Data @NoArgsConstructor @AllArgsConstructor @Builder public class AppAuthWeixinMiniAppLoginReqVO { @Schema(description = "手机 code,小程序通过 wx.getPhoneNumber 方法获得", requiredMode = Schema.RequiredMode.REQUIRED, example = "hello") @NotEmpty(message = "手机 code 不能为空") private String phoneCode; @Schema(description = "登录 code,小程序通过 wx.login 方法获得", requiredMode = Schema.RequiredMode.REQUIRED, example = "word") @NotEmpty(message = "登录 code 不能为空") private String loginCode; @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") @NotEmpty(message = "state 不能为空") private String state; }public interface MemberAuthService { /** * 手机 + 密码登录 * * @param reqVO 登录信息 * @return 登录结果 */ AppAuthLoginRespVO login(@Valid AppAuthLoginReqVO reqVO); /** * 基于 token 退出登录 * * @param token token */ void logout(String token); /** * 手机 + 验证码登陆 * * @param reqVO 登陆信息 * @return 登录结果 */ AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO); /** * 社交登录,使用 code 授权码 * * @param reqVO 登录信息 * @return 登录结果 */ AppAuthLoginRespVO socialLogin(@Valid AppAuthSocialLoginReqVO reqVO); /** * 微信小程序的一键登录 * * @param reqVO 登录信息 * @return 登录结果 */ AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO); /**@Override public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) { // 获得对应的手机号信息 SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo( UserTypeEnum.COOPERATIVE.getValue(), reqVO.getPhoneCode()); Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空"); // 获得获得注册用户 MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), getClientIP(), TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal()); Assert.notNull(user, "获取用户失败,结果为空"); // 绑定社交用户 String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), reqVO.getState())); // 创建 Token 令牌,记录登录日志 return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid); }
private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile,
LoginLogTypeEnum logType, String openid) {
// 插入登陆日志
createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
// 创建 Token 令牌
OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
.setUserId(user.getId()).setUserType(getUserType().getValue())
.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
// 构建返回结果
return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid);
}
private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile,
LoginLogTypeEnum logType, String openid) {
// 插入登陆日志
createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
// 创建 Token 令牌
OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
.setUserId(user.getId()).setUserType(getUserType().getValue())
.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
// 构建返回结果
return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid);
}
@Override
public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getTenantId(), reqDTO.getScopes());
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
public interface OAuth2TokenService {
/**
* 创建访问令牌
* 注意:该流程中,会包含创建刷新令牌的创建
*
* 参考 DefaultTokenServices 的 createAccessToken 方法
*
* @param userId 用户编号
* @param userType 用户类型
* @param clientId 客户端编号
* @param scopes 授权范围
* @return 访问令牌的信息
*/
OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes);
OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, Long tenantId, List<String> scopes);
@Override
@Transactional(rollbackFor = Exception.class)
public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, Long tenantId, List<String> scopes) {
OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
// 创建刷新令牌
OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, tenantId, clientDO, scopes);
// 创建访问令牌
return createOAuth2AccessToken(refreshTokenDO, clientDO);
}
private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, Long tenantId, OAuth2ClientDO clientDO, List<String> scopes) {
OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken())
.setUserId(userId).setUserType(userType)
.setClientId(clientDO.getClientId()).setScopes(scopes)
.setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds()));
refreshToken.setTenantId(tenantId);
oauth2RefreshTokenMapper.insert(refreshToken);
return refreshToken;
}
@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class OAuth2RefreshTokenDO extends TenantBaseDO {
/**
* 编号,数据库字典
*/
private Long id;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 客户端编号
*
* 关联 {@link OAuth2ClientDO#getId()}
*/
private String clientId;
/**
* 授权范围
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> scopes;
/**
* 过期时间
*/
private LocalDateTime expiresTime;
}
public class OAuth2AccessTokenDO extends TenantBaseDO {
/**
* 编号,数据库递增
*/
@TableId
private Long id;
/**
* 访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 用户信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, String> userInfo;
/**
* 客户端编号
*
* 关联 {@link OAuth2ClientDO#getId()}
*/
private String clientId;
/**
* 授权范围
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> scopes;
/**
* 过期时间
*/
private LocalDateTime expiresTime;
}
更多推荐
所有评论(0)