接入微信登录可以通过微信开放平台的授权登录功能实现,如何实现微信小程序使用微信登录案例

  1. 注册微信开放平台账号并创建应用:

首先注册微信开放平台账号,并在开发者中心创建一个应用,获取到AppID和AppSecret。

  1. 配置Spring Boot项目:

在application.properties或application.yml中配置微信登录的相关信息:

wechat.appId=your_app_id
wechat.appSecret=your_app_secret
wechat.redirectUrl=http://localhost:8080/login/wechat/callback

  1. 创建微信登录控制器:
  2.    @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;

}

    Logo

    北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

    更多推荐