202506100909

This commit is contained in:
张潘 2025-06-10 09:09:49 +08:00
parent 6cde8267fd
commit e4d903483f
26 changed files with 1640 additions and 1587 deletions

17
pom.xml
View File

@ -197,21 +197,6 @@
<artifactId>ruoyi-generator</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 微信认证-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-oauth-wx</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 微信认证-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-auth-common</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.ruoyi</groupId>
@ -271,8 +256,6 @@
<module>ruoyi-quartz</module>
<module>ruoyi-generator</module>
<module>ruoyi-common</module>
<module>ruoyi-oauth-wx</module>
<module>ruoyi-auth-common</module>
</modules>
<packaging>pom</packaging>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>hfrj</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-auth-common</artifactId>
<description>
system系统模块
</description>
<dependencies>
<!-- 核心模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
</dependency>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,293 +0,0 @@
package com.ruoyi.auth.common.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* 第三方认证对象 oauth_user
*
* @author Dftre
* @date 2024-01-18
*/
@Schema(description = "第三方认证对象")
public class OauthUser extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 */
@Schema(title = "主键")
private Long id;
/** 第三方系统的唯一ID详细解释请参考名词解释 */
@Schema(title = "第三方系统的唯一ID详细解释请参考名词解释")
@Excel(name = "第三方系统的唯一ID详细解释请参考名词解释")
private String uuid;
/** 用户ID */
@Schema(title = "用户ID")
@Excel(name = "用户ID")
private Long userId;
/**
* 第三方用户来源可选值GITHUBGITEEQQ更多请参考AuthDefaultSource.java(opens new window)
*/
@Schema(title = "第三方用户来源可选值GITHUB、GITEE、QQ更多请参考AuthDefaultSource.java(opens new window)")
@Excel(name = "第三方用户来源可选值GITHUB、GITEE、QQ更多请参考AuthDefaultSource.java(opens new window)")
private String source;
/** 用户的授权令牌 */
@Schema(title = "用户的授权令牌")
@Excel(name = "用户的授权令牌")
private String accessToken;
/** 第三方用户的授权令牌的有效期,部分平台可能没有 */
@Schema(title = "第三方用户的授权令牌的有效期,部分平台可能没有")
@Excel(name = "第三方用户的授权令牌的有效期,部分平台可能没有")
private Long expireIn;
/** 刷新令牌,部分平台可能没有 */
@Schema(title = "刷新令牌,部分平台可能没有")
@Excel(name = "刷新令牌,部分平台可能没有")
private String refreshToken;
/** 第三方用户的 open id部分平台可能没有 */
@Schema(title = "第三方用户的 open id部分平台可能没有")
@Excel(name = "第三方用户的 open id部分平台可能没有")
private String openId;
/** 第三方用户的 ID部分平台可能没有 */
@Schema(title = "第三方用户的 ID部分平台可能没有")
@Excel(name = "第三方用户的 ID部分平台可能没有")
private String uid;
/** 个别平台的授权信息,部分平台可能没有 */
@Schema(title = "个别平台的授权信息,部分平台可能没有")
@Excel(name = "个别平台的授权信息,部分平台可能没有")
private String accessCode;
/** 第三方用户的 union id部分平台可能没有 */
@Schema(title = "第三方用户的 union id部分平台可能没有")
@Excel(name = "第三方用户的 union id部分平台可能没有")
private String unionId;
/** 第三方用户授予的权限,部分平台可能没有 */
@Schema(title = "第三方用户授予的权限,部分平台可能没有")
@Excel(name = "第三方用户授予的权限,部分平台可能没有")
private String scope;
/** 个别平台的授权信息,部分平台可能没有 */
@Schema(title = "个别平台的授权信息,部分平台可能没有")
@Excel(name = "个别平台的授权信息,部分平台可能没有")
private String tokenType;
/** id token部分平台可能没有 */
@Schema(title = "id token部分平台可能没有")
@Excel(name = "id token部分平台可能没有")
private String idToken;
/** 小米平台用户的附带属性,部分平台可能没有 */
@Schema(title = "小米平台用户的附带属性,部分平台可能没有")
@Excel(name = "小米平台用户的附带属性,部分平台可能没有")
private String macAlgorithm;
/** 小米平台用户的附带属性,部分平台可能没有 */
@Schema(title = "小米平台用户的附带属性,部分平台可能没有")
@Excel(name = "小米平台用户的附带属性,部分平台可能没有")
private String macKey;
/** 用户的授权code部分平台可能没有 */
@Schema(title = "用户的授权code部分平台可能没有")
@Excel(name = "用户的授权code部分平台可能没有")
private String code;
/** Twitter平台用户的附带属性部分平台可能没有 */
@Schema(title = "Twitter平台用户的附带属性部分平台可能没有")
@Excel(name = "Twitter平台用户的附带属性部分平台可能没有")
private String oauthToken;
/** Twitter平台用户的附带属性部分平台可能没有 */
@Schema(title = "Twitter平台用户的附带属性部分平台可能没有")
@Excel(name = "Twitter平台用户的附带属性部分平台可能没有")
private String oauthTokenSecret;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getUuid() {
return uuid;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
public void setSource(String source) {
this.source = source;
}
public String getSource() {
return source;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getAccessToken() {
return accessToken;
}
public void setExpireIn(Long expireIn) {
this.expireIn = expireIn;
}
public Long getExpireIn() {
return expireIn;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getRefreshToken() {
return refreshToken;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getOpenId() {
return openId;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getUid() {
return uid;
}
public void setAccessCode(String accessCode) {
this.accessCode = accessCode;
}
public String getAccessCode() {
return accessCode;
}
public void setUnionId(String unionId) {
this.unionId = unionId;
}
public String getUnionId() {
return unionId;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getScope() {
return scope;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public String getTokenType() {
return tokenType;
}
public void setIdToken(String idToken) {
this.idToken = idToken;
}
public String getIdToken() {
return idToken;
}
public void setMacAlgorithm(String macAlgorithm) {
this.macAlgorithm = macAlgorithm;
}
public String getMacAlgorithm() {
return macAlgorithm;
}
public void setMacKey(String macKey) {
this.macKey = macKey;
}
public String getMacKey() {
return macKey;
}
public void setCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public void setOauthToken(String oauthToken) {
this.oauthToken = oauthToken;
}
public String getOauthToken() {
return oauthToken;
}
public void setOauthTokenSecret(String oauthTokenSecret) {
this.oauthTokenSecret = oauthTokenSecret;
}
public String getOauthTokenSecret() {
return oauthTokenSecret;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("uuid", getUuid())
.append("userId", getUserId())
.append("source", getSource())
.append("accessToken", getAccessToken())
.append("expireIn", getExpireIn())
.append("refreshToken", getRefreshToken())
.append("openId", getOpenId())
.append("uid", getUid())
.append("accessCode", getAccessCode())
.append("unionId", getUnionId())
.append("scope", getScope())
.append("tokenType", getTokenType())
.append("idToken", getIdToken())
.append("macAlgorithm", getMacAlgorithm())
.append("macKey", getMacKey())
.append("code", getCode())
.append("oauthToken", getOauthToken())
.append("oauthTokenSecret", getOauthTokenSecret())
.toString();
}
}

View File

@ -1,59 +0,0 @@
package com.ruoyi.auth.common.enums;
public enum OauthVerificationUse {
/** 用于登录 */
LOGIN("登录", "login"),
/** 用于注册 */
REGISTER("注册", "register"),
/** 用于禁用 */
DISABLE("禁用", "disable"),
/** 用于重置信息 */
RESET("重置", "reset"),
/** 用于绑定信息 */
BIND("绑定", "bind"),
/** 其他用途 */
OTHER("其他", "other");
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public static OauthVerificationUse getByValue(String value) {
for (OauthVerificationUse use : OauthVerificationUse.values()) {
if (use.getValue().equals(value)) {
return use;
}
}
return null;
}
public static OauthVerificationUse getByName(String name) {
for (OauthVerificationUse use : OauthVerificationUse.values()) {
if (use.getName().equals(name)) {
return use;
}
}
return null;
}
private OauthVerificationUse(String name, String value) {
this.name = name;
this.value = value;
}
}

View File

@ -1,112 +0,0 @@
package com.ruoyi.auth.common.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.auth.common.domain.OauthUser;
/**
* 第三方认证Mapper接口
*
* @author Dftre
* @date 2024-01-18
*/
public interface OauthUserMapper {
/**
* 查询第三方认证
*
* @param id 第三方认证主键
* @return 第三方认证
*/
public OauthUser selectOauthUserById(Long id);
public OauthUser selectOauthUserByUserId(Long userId);
/**
* 查询第三方认证
* 钉钉抖音uuid 为用户的 unionid
* 微信公众平台登录京东酷家乐美团uuid 为用户的 openId
* 微信开放平台登录QQuuid 为用户的 openId平台支持获取unionid unionid AuthToken
* 如果支持在登录完成后可以通过 response.getData().getToken().getUnionId() 获取
* Googleuuid 为用户的 subsub为Google的所有账户体系中用户唯一的身份标识符详见OpenID Connect
*
* @param uuid
* @return
*/
public OauthUser selectOauthUserByUUID(String uuid);
/**
* 查询第三方认证列表
*
* @param oauthUser 第三方认证
* @return 第三方认证集合
*/
public List<OauthUser> selectOauthUserList(OauthUser oauthUser);
/**
* 新增第三方认证
*
* @param oauthUser 第三方认证
* @return 结果
*/
public int insertOauthUser(OauthUser oauthUser);
/**
* 修改第三方认证
*
* @param oauthUser 第三方认证
* @return 结果
*/
public int updateOauthUser(OauthUser oauthUser);
/**
* 删除第三方认证
*
* @param id 第三方认证主键
* @return 结果
*/
public int deleteOauthUserById(Long id);
/**
* 批量删除第三方认证
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteOauthUserByIds(Long[] ids);
/**
* 校验source平台是否绑定
*
* @param userId 用户编号
* @param source 绑定平台
* @return 结果
*/
public int checkAuthUser(@Param("userId") Long userId, @Param("source") String source);
/**
* 校验用户名称是否唯一
*
* @param userName 用户名称
* @return 结果
*/
public int checkUserNameUnique(String userName);
/**
* 校验手机号码是否唯一
*
* @param phonenumber 手机号码
* @return 结果
*/
public int checkPhoneUnique(String phonenumber);
/**
* 校验email是否唯一
*
* @param email 用户邮箱
* @return 结果
*/
public int checkEmailUnique(String email);
}

View File

@ -1,102 +0,0 @@
package com.ruoyi.auth.common.service;
import java.util.List;
import com.ruoyi.auth.common.domain.OauthUser;
import com.ruoyi.common.core.domain.entity.SysUser;
/**
* 第三方认证Service接口
*
* @author Dftre
* @date 2024-01-18
*/
public interface IOauthUserService {
/**
* 查询第三方认证
*
* @param id 第三方认证主键
* @return 第三方认证
*/
public OauthUser selectOauthUserById(Long id);
public OauthUser selectOauthUserByUUID(String uuid);
public OauthUser selectOauthUserByUserId(Long userId);
public SysUser selectSysUserByUUID(String uuid);
/**
* 查询第三方认证列表
*
* @param oauthUser 第三方认证
* @return 第三方认证集合
*/
public List<OauthUser> selectOauthUserList(OauthUser oauthUser);
/**
* 新增第三方认证
*
* @param oauthUser 第三方认证
* @return 结果
*/
public int insertOauthUser(OauthUser oauthUser);
/**
* 修改第三方认证
*
* @param oauthUser 第三方认证
* @return 结果
*/
public int updateOauthUser(OauthUser oauthUser);
/**
* 批量删除第三方认证
*
* @param ids 需要删除的第三方认证主键集合
* @return 结果
*/
public int deleteOauthUserByIds(Long[] ids);
/**
* 删除第三方认证信息
*
* @param id 第三方认证主键
* @return 结果
*/
public int deleteOauthUserById(Long id);
/**
* 校验source平台是否绑定
*
* @param userId 用户编号
* @param source 绑定平台
* @return 结果
*/
public boolean checkAuthUser(Long userId, String source);
/**
* 校验用户名称是否唯一
*
* @param userName 用户名称
* @return 结果
*/
public boolean checkUserNameUnique(String userName);
/**
* 校验手机号码是否唯一
*
* @param phonenumber 手机号码
* @return 结果
*/
public boolean checkPhoneUnique(String phonenumber);
/**
* 校验email是否唯一
*
* @param email 用户邮箱
* @return 结果
*/
public boolean checkEmailUnique(String email);
}

View File

@ -1,15 +0,0 @@
package com.ruoyi.auth.common.service;
import com.ruoyi.auth.common.enums.OauthVerificationUse;
/**
* code认证方式接口
*
* @author zlh
* @date 2024-04-16
*/
public interface OauthVerificationCodeService {
public boolean sendCode(String o, String code,OauthVerificationUse use) throws Exception;
public boolean checkCode(String o, String code,OauthVerificationUse use) throws Exception;
}

View File

@ -1,73 +0,0 @@
package com.ruoyi.auth.common.service;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.RegisterBody;
/**
* 双因素认证TFA操作的服务接口
* 该接口提供处理TFA绑定注册和登录流程的方法
* 包括它们的验证步骤
*
* <p>
* 双因素认证通过要求用户提供两种不同的认证因素
* 为认证过程增加了额外的安全层
* </p>
*/
public interface TfaService {
/**
* 启动将TFA方法绑定到用户账户的流程
*
* @param loginBody 包含TFA绑定所需数据的登录信息
*/
public void doBind(LoginBody loginBody);
/**
* 使用验证码或其他确认方式验证TFA绑定流程
*
* @param loginBody 包含验证数据的登录信息
*/
public void doBindVerify(LoginBody loginBody);
/**
* 处理包含TFA设置的注册流程
*
* @param registerBody 包含用户详情和TFA设置的注册信息
*/
public void doRegister(RegisterBody registerBody);
/**
* 验证包含TFA设置的注册流程
*
* @param registerBody 包含验证数据的注册信息
*/
public void doRegisterVerify(RegisterBody registerBody);
/**
* 启动TFA登录流程的第一步
*
* @param loginBody 包含用户凭证的登录信息
*/
public void doLogin(LoginBody loginBody, boolean autoRegister);
/**
* 验证TFA登录流程的第二步并完成认证
*
* @param loginBody 包含TFA验证码的登录信息
* @return 已认证会话的字符串令牌或会话标识符
*/
public String doLoginVerify(LoginBody loginBody, boolean autoRegister);
/**
* 启动TFA重置流程的第一步
*
* @param registerBody 包含用户凭证的注册信息
*/
public void doReset(RegisterBody registerBody);
/**
* 验证TFA重置流程的第二步并完成重置
*
* @param registerBody 包含TFA验证码的注册信息
*/
public void doResetVerify(RegisterBody registerBody);
}

View File

@ -1,149 +0,0 @@
package com.ruoyi.auth.common.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.auth.common.domain.OauthUser;
import com.ruoyi.auth.common.mapper.OauthUserMapper;
import com.ruoyi.auth.common.service.IOauthUserService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.mapper.SysUserMapper;
/**
* 第三方认证Service业务层处理
*
* @author Dftre
* @date 2024-01-18
*/
@Service
public class OauthUserServiceImpl implements IOauthUserService {
@Autowired
private OauthUserMapper oauthUserMapper;
@Autowired
private SysUserMapper sysUserMapper;
/**
* 查询第三方认证
*
* @param id 第三方认证主键
* @return 第三方认证
*/
@Override
public OauthUser selectOauthUserById(Long id) {
return oauthUserMapper.selectOauthUserById(id);
}
@Override
public OauthUser selectOauthUserByUUID(String uuid) {
return oauthUserMapper.selectOauthUserByUUID(uuid);
}
@Override
public OauthUser selectOauthUserByUserId(Long userId) {
return oauthUserMapper.selectOauthUserByUserId(userId);
}
/**
* 查询第三方认证列表
*
* @param oauthUser 第三方认证
* @return 第三方认证
*/
@Override
public List<OauthUser> selectOauthUserList(OauthUser oauthUser) {
return oauthUserMapper.selectOauthUserList(oauthUser);
}
/**
* 新增第三方认证
*
* @param oauthUser 第三方认证
* @return 结果
*/
@Override
public int insertOauthUser(OauthUser oauthUser) {
return oauthUserMapper.insertOauthUser(oauthUser);
}
/**
* 修改第三方认证
*
* @param oauthUser 第三方认证
* @return 结果
*/
@Override
public int updateOauthUser(OauthUser oauthUser) {
return oauthUserMapper.updateOauthUser(oauthUser);
}
/**
* 批量删除第三方认证
*
* @param ids 需要删除的第三方认证主键
* @return 结果
*/
@Override
public int deleteOauthUserByIds(Long[] ids) {
return oauthUserMapper.deleteOauthUserByIds(ids);
}
/**
* 删除第三方认证信息
*
* @param id 第三方认证主键
* @return 结果
*/
@Override
public int deleteOauthUserById(Long id) {
return oauthUserMapper.deleteOauthUserById(id);
}
public SysUser selectSysUserByUUID(String uuid) {
OauthUser oauthUser = oauthUserMapper.selectOauthUserByUUID(uuid);
return sysUserMapper.selectUserById(oauthUser.getUserId());
}
/**
* 校验source平台是否绑定
*
* @param userId 用户编号
* @param source 绑定平台
* @return 结果
*/
public boolean checkAuthUser(Long userId, String source) {
return oauthUserMapper.checkAuthUser(userId, source) > 0;
};
/**
* 校验用户名称是否唯一
*
* @param userName 用户名称
* @return 结果
*/
public boolean checkUserNameUnique(String userName) {
return oauthUserMapper.checkUserNameUnique(userName) > 0;
};
/**
* 校验手机号码是否唯一
*
* @param phonenumber 手机号码
* @return 结果
*/
public boolean checkPhoneUnique(String phonenumber) {
return oauthUserMapper.checkPhoneUnique(phonenumber) > 0;
};
/**
* 校验email是否唯一
*
* @param email 用户邮箱
* @return 结果
*/
public boolean checkEmailUnique(String email) {
return oauthUserMapper.checkEmailUnique(email) > 0;
};
}

View File

@ -1,28 +0,0 @@
package com.ruoyi.auth.common.utils;
import java.security.SecureRandom;
public class RandomCodeUtil {
public static String randomString(String characters, int length) {
StringBuilder result = new StringBuilder();
SecureRandom random = new SecureRandom();
for (int i = 0; i < length; i++) {
int index = random.nextInt(characters.length());
result.append(characters.charAt(index));
}
return result.toString();
}
public static String numberCode(int length) {
String characters = "0123456789";
return randomString(characters, length);
}
public static String code(int length) {
String characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
return randomString(characters, length);
}
}

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.auth.common.mapper.OauthUserMapper">
<resultMap type="OauthUser" id="OauthUserResult">
<result property="id" column="id" />
<result property="uuid" column="uuid" />
<result property="userId" column="user_id" />
<result property="source" column="source" />
<result property="accessToken" column="access_token" />
<result property="expireIn" column="expire_in" />
<result property="refreshToken" column="refresh_token" />
<result property="openId" column="open_id" />
<result property="uid" column="uid" />
<result property="accessCode" column="access_code" />
<result property="unionId" column="union_id" />
<result property="scope" column="scope" />
<result property="tokenType" column="token_type" />
<result property="idToken" column="id_token" />
<result property="macAlgorithm" column="mac_algorithm" />
<result property="macKey" column="mac_key" />
<result property="code" column="code" />
<result property="oauthToken" column="oauth_token" />
<result property="oauthTokenSecret" column="oauth_token_secret" />
</resultMap>
<sql id="selectOauthUserVo">
select id, uuid, user_id, source, access_token, expire_in, refresh_token, open_id, uid, access_code, union_id, scope, token_type, id_token, mac_algorithm, mac_key, code, oauth_token, oauth_token_secret from oauth_user
</sql>
<select id="checkUserNameUnique" parameterType="String" resultType="int">
select count(1) from sys_user where user_name = #{userName} and del_flag = '0' limit 1
</select>
<select id="checkPhoneUnique" parameterType="String" resultType="int">
select count(1) from sys_user where phonenumber = #{phonenumber} and del_flag = '0' limit 1
</select>
<select id="checkEmailUnique" parameterType="String" resultType="int">
select count(1) from sys_user where email = #{email} and del_flag = '0' limit 1
</select>
<select id="checkAuthUser" parameterType="OauthUser" resultType="int">
select count(1) from oauth_user where user_id=#{userId} and source=#{source} limit 1
</select>
<select id="selectOauthUserList" parameterType="OauthUser" resultMap="OauthUserResult">
<include refid="selectOauthUserVo"/>
<where>
<if test="uuid != null and uuid != ''"> and uuid = #{uuid}</if>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="source != null and source != ''"> and source = #{source}</if>
<if test="accessToken != null and accessToken != ''"> and access_token = #{accessToken}</if>
<if test="expireIn != null "> and expire_in = #{expireIn}</if>
<if test="refreshToken != null and refreshToken != ''"> and refresh_token = #{refreshToken}</if>
<if test="openId != null and openId != ''"> and open_id = #{openId}</if>
<if test="uid != null and uid != ''"> and uid = #{uid}</if>
<if test="accessCode != null and accessCode != ''"> and access_code = #{accessCode}</if>
<if test="unionId != null and unionId != ''"> and union_id = #{unionId}</if>
<if test="scope != null and scope != ''"> and scope = #{scope}</if>
<if test="tokenType != null and tokenType != ''"> and token_type = #{tokenType}</if>
<if test="idToken != null and idToken != ''"> and id_token = #{idToken}</if>
<if test="macAlgorithm != null and macAlgorithm != ''"> and mac_algorithm = #{macAlgorithm}</if>
<if test="macKey != null and macKey != ''"> and mac_key = #{macKey}</if>
<if test="code != null and code != ''"> and code = #{code}</if>
<if test="oauthToken != null and oauthToken != ''"> and oauth_token = #{oauthToken}</if>
<if test="oauthTokenSecret != null and oauthTokenSecret != ''"> and oauth_token_secret = #{oauthTokenSecret}</if>
</where>
</select>
<select id="selectOauthUserById" parameterType="Long" resultMap="OauthUserResult">
<include refid="selectOauthUserVo"/>
where oauth_user.id = #{id}
</select>
<select id="selectOauthUserByUserId" parameterType="Long" resultMap="OauthUserResult">
<include refid="selectOauthUserVo"/>
where oauth_user.user_id = #{user_id}
</select>
<select id="selectOauthUserByUUID" parameterType="String" resultMap="OauthUserResult">
<include refid="selectOauthUserVo"/>
where oauth_user.uuid = #{uuid}
</select>
<insert id="insertOauthUser" parameterType="OauthUser">
insert into oauth_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="uuid != null and uuid != ''">uuid,</if>
<if test="userId != null">user_id,</if>
<if test="source != null and source != ''">source,</if>
<if test="accessToken != null and accessToken != ''">access_token,</if>
<if test="expireIn != null">expire_in,</if>
<if test="refreshToken != null">refresh_token,</if>
<if test="openId != null">open_id,</if>
<if test="uid != null">uid,</if>
<if test="accessCode != null">access_code,</if>
<if test="unionId != null">union_id,</if>
<if test="scope != null">scope,</if>
<if test="tokenType != null">token_type,</if>
<if test="idToken != null">id_token,</if>
<if test="macAlgorithm != null">mac_algorithm,</if>
<if test="macKey != null">mac_key,</if>
<if test="code != null">code,</if>
<if test="oauthToken != null">oauth_token,</if>
<if test="oauthTokenSecret != null">oauth_token_secret,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="uuid != null and uuid != ''">#{uuid},</if>
<if test="userId != null">#{userId},</if>
<if test="source != null and source != ''">#{source},</if>
<if test="accessToken != null and accessToken != ''">#{accessToken},</if>
<if test="expireIn != null">#{expireIn},</if>
<if test="refreshToken != null">#{refreshToken},</if>
<if test="openId != null">#{openId},</if>
<if test="uid != null">#{uid},</if>
<if test="accessCode != null">#{accessCode},</if>
<if test="unionId != null">#{unionId},</if>
<if test="scope != null">#{scope},</if>
<if test="tokenType != null">#{tokenType},</if>
<if test="idToken != null">#{idToken},</if>
<if test="macAlgorithm != null">#{macAlgorithm},</if>
<if test="macKey != null">#{macKey},</if>
<if test="code != null">#{code},</if>
<if test="oauthToken != null">#{oauthToken},</if>
<if test="oauthTokenSecret != null">#{oauthTokenSecret},</if>
</trim>
</insert>
<update id="updateOauthUser" parameterType="OauthUser">
update oauth_user
<trim prefix="SET" suffixOverrides=",">
<if test="uuid != null and uuid != ''">uuid = #{uuid},</if>
<if test="userId != null">user_id = #{userId},</if>
<if test="source != null and source != ''">source = #{source},</if>
<if test="accessToken != null and accessToken != ''">access_token = #{accessToken},</if>
<if test="expireIn != null">expire_in = #{expireIn},</if>
<if test="refreshToken != null">refresh_token = #{refreshToken},</if>
<if test="openId != null">open_id = #{openId},</if>
<if test="uid != null">uid = #{uid},</if>
<if test="accessCode != null">access_code = #{accessCode},</if>
<if test="unionId != null">union_id = #{unionId},</if>
<if test="scope != null">scope = #{scope},</if>
<if test="tokenType != null">token_type = #{tokenType},</if>
<if test="idToken != null">id_token = #{idToken},</if>
<if test="macAlgorithm != null">mac_algorithm = #{macAlgorithm},</if>
<if test="macKey != null">mac_key = #{macKey},</if>
<if test="code != null">code = #{code},</if>
<if test="oauthToken != null">oauth_token = #{oauthToken},</if>
<if test="oauthTokenSecret != null">oauth_token_secret = #{oauthTokenSecret},</if>
</trim>
where oauth_user.id = #{id}
</update>
<delete id="deleteOauthUserById" parameterType="Long">
delete from oauth_user where id = #{id}
</delete>
<delete id="deleteOauthUserByIds" parameterType="String">
delete from oauth_user where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -90,6 +90,9 @@ public class BaseController
return rspData;
}
/**
* 返回成功
*/

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>hfrj</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-oauth-wx</artifactId>
<description>
微信认证模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-auth-common</artifactId>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,42 +0,0 @@
package com.ruoyi.oauth.wx.constant;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WxMiniAppConstant {
@Value("${oauth.wx.miniapp.appId}")
private String appId;
@Value("${oauth.wx.miniapp.appSecret}")
private String appSecret;
@Value("${oauth.wx.miniapp.url}")
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
}

View File

@ -1,41 +0,0 @@
package com.ruoyi.oauth.wx.constant;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WxPubConstant {
@Value("${oauth.wx.pub.appId}")
private String appId;
@Value("${oauth.wx.pub.appSecret}")
private String appSecret;
@Value("${oauth.wx.pub.url}")
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
}

View File

@ -1,69 +0,0 @@
package com.ruoyi.oauth.wx.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.auth.common.domain.OauthUser;
import com.ruoyi.auth.common.service.IOauthUserService;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oauth.wx.service.Impl.WxMiniAppLoginServiceImpl;
import com.ruoyi.oauth.wx.service.Impl.WxPubLoginServiceImpl;
@RestController
@RequestMapping("/oauth/wx")
public class WxLoginController extends BaseController {
@Autowired
private IOauthUserService oauthUserService;
@Autowired
private WxMiniAppLoginServiceImpl wxMiniAppLoginServiceImpl;
@Autowired
private WxPubLoginServiceImpl wxPubLoginServiceImpl;
@Anonymous
@PostMapping("/login/{source}/{code}")
public AjaxResult loginMiniApp(@PathVariable("source") String source, @PathVariable("code") String code) {
String token = null;
AjaxResult ajax = AjaxResult.success();
if ("miniapp".equals(source)) {
token = wxMiniAppLoginServiceImpl.doLogin(code);
} else if ("pub".equals(source)) {
token = wxPubLoginServiceImpl.doLogin(code);
} else {
return error("错误的登录方式");
}
ajax.put(Constants.TOKEN, token);
return ajax;
}
@PostMapping("/register/{source}/{code}")
public AjaxResult register(@PathVariable("source") String source, @PathVariable("code") String code) {
OauthUser oauthUser = oauthUserService.selectOauthUserByUserId(getUserId());
if (oauthUser != null) {
return error("不可以重复绑定");
} else {
String msg = "";
oauthUser = new OauthUser();
oauthUser.setUserId(getUserId());
oauthUser.setCode(code);
if ("miniapp".equals(source)) {
msg = wxMiniAppLoginServiceImpl.doRegister(oauthUser);
} else if ("pub".equals(source)) {
msg = wxPubLoginServiceImpl.doRegister(oauthUser);
} else {
return error("错误的注册方式");
}
return StringUtils.isEmpty(msg) ? success() : error(msg);
}
}
}

View File

@ -1,76 +0,0 @@
package com.ruoyi.oauth.wx.service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.auth.common.domain.OauthUser;
import com.ruoyi.auth.common.service.IOauthUserService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.web.service.UserDetailsServiceImpl;
import com.ruoyi.oauth.wx.constant.WxMiniAppConstant;
import com.ruoyi.oauth.wx.service.WxLoginService;
import com.ruoyi.system.service.ISysUserService;
@Service
public class WxMiniAppLoginServiceImpl implements WxLoginService {
@Autowired
private WxMiniAppConstant wxAppConstant;
@Autowired
private TokenService tokenService;
@Autowired
private UserDetailsServiceImpl userDetailsServiceImpl;
@Autowired
private ISysUserService userService;
@Autowired
private IOauthUserService oauthUserService;
@Override
public String doLogin(String code) {
String openid = doAuth(
wxAppConstant.getUrl(),
wxAppConstant.getAppId(),
wxAppConstant.getAppSecret(),
code).getString("openid");
OauthUser selectOauthUser = oauthUserService.selectOauthUserByUUID(openid);
if (selectOauthUser == null) {
return null;
}
SysUser sysUser = userService.selectUserById(selectOauthUser.getUserId());
if (sysUser == null) {
throw new ServiceException("该微信未绑定用户");
}
LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser);
return tokenService.createToken(loginUser);
}
@Override
public String doRegister(OauthUser oauthUser) {
if (StringUtils.isEmpty(oauthUser.getCode())) {
return "没有凭证";
}
if (oauthUser.getUserId() == null) {
return "请先注册账号";
}
JSONObject doAuth = doAuth(
wxAppConstant.getUrl(),
wxAppConstant.getAppId(),
wxAppConstant.getAppSecret(),
oauthUser.getCode());
oauthUser.setOpenId(doAuth.getString("openid"));
oauthUser.setUuid(doAuth.getString("openid"));
oauthUser.setSource("WXMiniApp");
oauthUser.setAccessToken(doAuth.getString("sessionKey"));
oauthUserService.insertOauthUser(oauthUser);
return "";
}
}

View File

@ -1,77 +0,0 @@
package com.ruoyi.oauth.wx.service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.auth.common.domain.OauthUser;
import com.ruoyi.auth.common.service.IOauthUserService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.web.service.UserDetailsServiceImpl;
import com.ruoyi.oauth.wx.constant.WxPubConstant;
import com.ruoyi.oauth.wx.service.WxLoginService;
import com.ruoyi.system.service.ISysUserService;
@Service
public class WxPubLoginServiceImpl implements WxLoginService {
@Autowired
private WxPubConstant wxH5Constant;
@Autowired
private TokenService tokenService;
@Autowired
private UserDetailsServiceImpl userDetailsServiceImpl;
@Autowired
private ISysUserService userService;
@Autowired
private IOauthUserService oauthUserService;
@Override
public String doLogin(String code) {
String openid = doAuth(
wxH5Constant.getUrl(),
wxH5Constant.getAppId(),
wxH5Constant.getAppSecret(),
code).getString("openid");
OauthUser selectOauthUser = oauthUserService.selectOauthUserByUUID(openid);
if (selectOauthUser == null) {
return null;
}
SysUser sysUser = userService.selectUserById(selectOauthUser.getUserId());
if (sysUser == null) {
throw new ServiceException("该微信未绑定用户");
}
LoginUser loginUser = (LoginUser) userDetailsServiceImpl.createLoginUser(sysUser);
return tokenService.createToken(loginUser);
}
@Override
public String doRegister(OauthUser oauthUser) {
if (StringUtils.isEmpty(oauthUser.getCode())) {
return "没有凭证";
}
if (oauthUser.getUserId() == null) {
return "请先注册账号";
}
JSONObject doAuth = doAuth(
wxH5Constant.getUrl(),
wxH5Constant.getAppId(),
wxH5Constant.getAppSecret(),
oauthUser.getCode());
oauthUser.setOpenId(doAuth.getString("openid"));
oauthUser.setUuid(doAuth.getString("openid"));
oauthUser.setSource("WXPub");
oauthUser.setAccessToken(doAuth.getString("sessionKey"));
oauthUserService.insertOauthUser(oauthUser);
return "";
}
}

View File

@ -1,34 +0,0 @@
package com.ruoyi.oauth.wx.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.auth.common.domain.OauthUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.http.HttpClientUtil;
public interface WxLoginService {
public String doLogin(String code);
public String doRegister(OauthUser oauthUser);
public default JSONObject doAuth(String url, String appid, String secret, String code) {
StringBuilder builder = new StringBuilder(url);
builder.append("?appid=").append(appid)
.append("&secret=").append(secret)
.append("&js_code=").append(code)
.append("&grant_type=").append("authorization_code");
String getMessageUrl = builder.toString();
String result = HttpClientUtil.sendHttpGet(getMessageUrl);
JSONObject jsonObject = JSON.parseObject(result);
if (jsonObject.containsKey("openid")) {
String openid = jsonObject.getString("openid");
String sessionKey = jsonObject.getString("session_key");
System.out.println("openid:" + openid);
System.out.println("sessionKey:" + sessionKey);
return jsonObject;
} else {
throw new ServiceException(jsonObject.getString("errmsg"), jsonObject.getIntValue("errcode"));
}
}
}

View File

@ -1,20 +0,0 @@
{
"properties": [
{
"name": "oauth.wx.miniapp.app-id",
"type": "java.lang.String",
"description": "wx73d0202b3c8a6d68"
},
{
"name": "oauth.wx.miniapp.app-secret",
"type": "java.lang.String",
"description": "c0871da0ca140930420c695147f3694b"
},
{
"name": "oauth.wx.miniapp.url",
"type": "java.lang.String",
"description": "微信小程序认证地址"
}
]
}

View File

@ -24,13 +24,6 @@
</dependency>
<!-- 微信认证-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-oauth-wx</artifactId>
</dependency>
<!-- 七牛云存储 -->
<dependency>
<groupId>com.qiniu</groupId>

View File

@ -1,13 +1,18 @@
package com.ruoyi.system.controller;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.ControllerUtil.WechatApiUtil;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
@ -16,8 +21,12 @@ import java.util.Map;
import org.springframework.web.bind.annotation.RequestBody;
import com.ruoyi.system.ControllerUtil.AppletControllerUtil;
import com.ruoyi.system.ControllerUtil.AppletLoginUtil;
import com.ruoyi.system.ControllerUtil.PageUtil;
import static com.ruoyi.common.core.domain.AjaxResult.error;
import static com.ruoyi.common.core.domain.AjaxResult.success;
import static com.ruoyi.common.utils.PageUtils.startPage;
import com.github.pagehelper.PageHelper;
/**
* 小程序控制器
@ -35,7 +44,7 @@ import static com.ruoyi.common.core.domain.AjaxResult.success;
* @version 1.0
*/
@RestController
public class AppletController {
public class AppletController extends BaseController {
@Autowired
private IServiceCateService serviceCateService;
@ -47,6 +56,8 @@ public class AppletController {
private IAdvImgService advImgService;
@Autowired
private IServiceGoodsService serviceGoodsService;
@Autowired
private IUserAddressService userAddressService;
/**
* 获取服务分类列表
*
@ -127,6 +138,113 @@ public class AppletController {
}
}
@GetMapping(value = "/api/public/get/config")
public AjaxResult getconfig(HttpServletRequest request) {
SiteConfig configQuery = new SiteConfig();
configQuery.setName("config_one");
List<SiteConfig> list = siteConfigService.selectSiteConfigList(configQuery);
return success(list.get(0).getValue());
}
/**
* 查询用户收货地址列表
*
* @param limit 每页显示数量
* @param page 页码
* @param request HTTP请求对象
* @return 分页地址列表
*
* 请求参数
* - limit: 每页显示数量默认15
* - page: 页码默认1
*
* 返回格式
* {
* "code": 200,
* "msg": "OK",
* "data": {
* "current_page": 1,
* "data": [...],
* "from": 1,
* "last_page": 1,
* "next_page_url": null,
* "per_page": "15",
* "prev_page_url": null,
* "to": 1,
* "total": 1
* }
* }
*/
@GetMapping("/api/user/address/list")
public AjaxResult getaddresslist(
@RequestParam(value = "limit", defaultValue = "15") int limit,
@RequestParam(value = "page", defaultValue = "1") int page,
HttpServletRequest request) {
try {
// 1. 验证分页参数
Map<String, Object> pageValidation = PageUtil.validatePageParams(page, limit);
if (!(Boolean) pageValidation.get("valid")) {
return error((String) pageValidation.get("message"));
}
// 2. 验证用户登录状态
String token = request.getHeader("token");
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
if (!(Boolean) userValidation.get("valid")) {
return error("用户未登录或token无效");
}
// 3. 获取用户信息
Users user = (Users) userValidation.get("user");
if (user == null) {
return error("用户信息获取失败");
}
// 4. 设置分页参数
PageHelper.startPage(page, limit);
// 5. 查询用户地址列表
UserAddress userAddressQuery = new UserAddress();
userAddressQuery.setUid(user.getId());
List<UserAddress> addressList = userAddressService.selectUserAddressList(userAddressQuery);
// 6. 获取分页信息并构建响应
TableDataInfo tableDataInfo = getDataTable(addressList);
// 7. 构建符合要求的分页响应格式
Map<String, Object> pageData = PageUtil.buildPageResponse(tableDataInfo, page, limit);
return success(pageData);
} catch (Exception e) {
System.err.println("查询用户地址列表异常:" + e.getMessage());
return error("查询地址列表失败:" + e.getMessage());
}
}
@PostMapping(value = "/api/user/login")
public AjaxResult getuserlogin(HttpServletRequest request) {
String token=request.getHeader("token");
Users users=usersService.selectUsersByRememberToken(token);
if (users!=null){
users.setRemember_token(users.getRememberToken());
return success(users);
}else{
return error("用户不存在");
}
}
/**
* 获取服务商品列表
* 前端参数格式{cate_id: 18, keywords:"dfffff"}
@ -267,13 +385,14 @@ public class AppletController {
/**
* 微信用户登录接口
*
* @param params 请求参数包含openid
* @param params 请求参数
* @param request HTTP请求对象
* @return 登录结果
*
* 请求参数格式
* {
* "openid": "微信用户openid"
* "usercode": "微信小程序登录code",
* "code": "手机号授权code"
* }
*
* 返回数据格式
@ -281,50 +400,59 @@ public class AppletController {
* "code": 200,
* "msg": "操作成功",
* "data": {
* "success": true,
* "token": "用户token",
* "userInfo": {...},
* "isNewUser": true/false,
* "message": "登录成功"
* "user": {
* "id": 用户ID,
* "phone": "手机号",
* "name": "用户名",
* "openid": "微信openid",
* "remember_token": "用户token",
* "avatar": "头像地址",
* "isNewUser": true/false
* }
* }
* }
*
* 接口说明
* - 验证微信openid的有效性
* - 首次登录自动创建用户记录
* - 再次登录更新用户信息和token
* - 生成用户唯一身份token
* - 支持用户信息同步更新
* 登录流程
* 1. 验证请求参数
* 2. 通过usercode获取微信openid
* 3. 检查用户是否已存在通过openid
* 4. 如果用户存在直接返回用户信息
* 5. 如果用户不存在获取手机号并创建/更新用户
*/
@PostMapping(value = "/api/wechat/login")
@PostMapping(value = "/api/user/phone/login")
public AjaxResult wechatLogin(@RequestBody Map<String, Object> params, HttpServletRequest request) {
try {
// 1. 参数验证
if (params == null || !params.containsKey("openid")) {
return error("请求参数不能为空需要提供openid");
// 使用AppletLoginUtil执行完整的微信登录流程
return AppletLoginUtil.executeWechatLogin(params, usersService);
}
String openid = (String) params.get("openid");
if (openid == null || openid.trim().isEmpty()) {
return error("openid不能为空");
}
// 2. 调用登录方法
Map<String, Object> loginResult = AppletControllerUtil.wechatUserLogin(openid.trim(), usersService);
// 3. 判断登录结果
boolean success = (Boolean) loginResult.get("success");
if (success) {
return success(loginResult);
@GetMapping(value = "/api/user/info")
public AjaxResult getUserByPhone(HttpServletRequest request) {
String token=request.getHeader("token");
Map<String, Object> order_num=new HashMap<>();
Map<String, Object> goods_order_num=new HashMap<>();
Users users=usersService.selectUsersByRememberToken(token);
if (users!=null){
users.setRemember_token(users.getRememberToken());
order_num.put("pending_accept",2);
order_num.put("pending_service",0);
order_num.put("in_service",0);
order_num.put("other_status",0);
users.setOrder_num(order_num);
goods_order_num.put("pending_accept",0);
goods_order_num.put("pending_service",3);
goods_order_num.put("in_service",0);
goods_order_num.put("other_status",0);
users.setGoods_order_num(goods_order_num);
return success(users);
}else{
return error((String) loginResult.get("message"));
return error("用户不存在");
}
} catch (Exception e) {
return error("微信登录失败:" + e.getMessage());
}
}
/**
* 验证用户token接口
*
@ -357,21 +485,17 @@ public class AppletController {
public AjaxResult validateToken(HttpServletRequest request) {
try {
// 1. 获取token
String token = request.getHeader("token");
if (token == null || token.trim().isEmpty()) {
// 尝试从Authorization头获取
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
token = authHeader.substring(7);
}
}
String token = AppletLoginUtil.extractToken(
request.getHeader("Authorization"),
request.getHeader("token")
);
if (token == null || token.trim().isEmpty()) {
if (token == null) {
return error("未提供token请先登录");
}
// 2. 验证token
Map<String, Object> validateResult = AppletControllerUtil.validateUserToken(token.trim(), usersService);
Map<String, Object> validateResult = AppletLoginUtil.validateUserToken(token, usersService);
// 3. 返回验证结果
boolean valid = (Boolean) validateResult.get("valid");
@ -392,7 +516,7 @@ public class AppletController {
/**
* 获取服务商品详细信息
*
* @param id 商品ID
* @param params 商品ID
* @param request HTTP请求对象
* @return 商品详细信息
*
@ -455,7 +579,7 @@ public class AppletController {
try {
// 1. 验证用户登录状态
String token = request.getHeader("token");
Map<String, Object> userValidation = AppletControllerUtil.validateUserToken(token, usersService);
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
if (!(Boolean) userValidation.get("valid")) {
return error("用户未登录或token无效");
}
@ -488,7 +612,7 @@ public class AppletController {
try {
// 1. 验证用户登录状态
String token = request.getHeader("token");
Map<String, Object> userValidation = AppletControllerUtil.validateUserToken(token, usersService);
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
if (!(Boolean) userValidation.get("valid")) {
return error("用户未登录或token无效");
}
@ -532,7 +656,7 @@ public class AppletController {
try {
// 1. 验证用户登录状态
String token = request.getHeader("token");
Map<String, Object> userValidation = AppletControllerUtil.validateUserToken(token, usersService);
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
if (!(Boolean) userValidation.get("valid")) {
return error("用户未登录或token无效");
}
@ -612,7 +736,7 @@ public class AppletController {
try {
// 1. 验证用户登录状态
String token = request.getHeader("token");
Map<String, Object> userValidation = AppletControllerUtil.validateUserToken(token, usersService);
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
if (!(Boolean) userValidation.get("valid")) {
return error("用户未登录或token无效");
}
@ -653,7 +777,7 @@ public class AppletController {
try {
// 1. 验证用户登录状态这里可能需要管理员权限
String token = request.getHeader("token");
Map<String, Object> userValidation = AppletControllerUtil.validateUserToken(token, usersService);
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
if (!(Boolean) userValidation.get("valid")) {
return error("用户未登录或token无效");
}

View File

@ -0,0 +1,374 @@
package com.ruoyi.system.ControllerUtil;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.Users;
import com.ruoyi.system.service.IUsersService;
import java.util.HashMap;
import java.util.Map;
import static com.ruoyi.common.core.domain.AjaxResult.error;
import static com.ruoyi.common.core.domain.AjaxResult.success;
/**
* 小程序登录工具类
*
* 提供微信小程序登录相关的工具方法
* 主要功能
* 1. 参数验证和提取
* 2. 微信openid获取
* 3. 用户手机号获取
* 4. 用户创建和更新
* 5. 登录响应构建
*
* @author Mr. Zhang Pan
* @date 2025-01-03
* @version 1.0
*/
public class AppletLoginUtil {
/**
* 执行微信登录完整流程
*
* @param params 登录参数
* @param usersService 用户服务
* @return 登录结果
*/
public static AjaxResult executeWechatLogin(Map<String, Object> params, IUsersService usersService) {
try {
// 1. 参数验证
String jsCode = validateAndExtractParam(params, "usercode", "微信登录code不能为空");
String phoneCode = validateAndExtractParam(params, "code", "手机号授权code不能为空");
// 2. 获取微信openid
String openid = getWechatOpenid(jsCode);
if (openid == null) {
return error("获取微信openid失败请重试");
}
// 3. 检查用户是否已存在
Users existingUser = usersService.selectUsersByOpenid(openid);
if (existingUser != null) {
existingUser.setRemember_token(existingUser.getRememberToken());
return buildSuccessResponse(existingUser, false);
}
// 4. 新用户处理获取手机号并创建用户
String phoneNumber = getPhoneNumber(phoneCode);
if (phoneNumber == null) {
return error("获取手机号失败,请重新授权");
}
// 5. 创建或更新用户
Users user = createOrUpdateUser(openid, phoneNumber, usersService);
user.setRemember_token(user.getRememberToken());
return buildSuccessResponse(user, true);
} catch (IllegalArgumentException e) {
return error(e.getMessage());
} catch (Exception e) {
System.err.println("微信登录异常:" + e.getMessage());
e.printStackTrace();
return error("微信登录失败,请稍后重试");
}
}
/**
* 验证并提取请求参数
*
* @param params 参数Map
* @param key 参数键
* @param errorMessage 错误信息
* @return 参数值
* @throws IllegalArgumentException 参数无效时抛出
*/
public static String validateAndExtractParam(Map<String, Object> params, String key, String errorMessage) {
Object value = params.get(key);
if (value == null || value.toString().trim().isEmpty()) {
throw new IllegalArgumentException(errorMessage);
}
return value.toString().trim();
}
/**
* 获取微信openid
*
* @param jsCode 微信小程序登录code
* @return openid或null
*/
public static String getWechatOpenid(String jsCode) {
try {
Map<String, Object> openidResult = WechatApiUtil.getWechatUserOpenidInfo(jsCode);
if (!(Boolean) openidResult.get("success")) {
System.err.println("获取openid失败" + openidResult.get("errorMsg"));
return null;
}
String openid = (String) openidResult.get("openid");
if (openid == null || openid.trim().isEmpty()) {
System.err.println("微信API返回的openid为空");
return null;
}
System.out.println("成功获取微信openid" + openid.substring(0, 8) + "...");
return openid;
} catch (Exception e) {
System.err.println("获取微信openid异常" + e.getMessage());
return null;
}
}
/**
* 获取用户手机号
*
* @param phoneCode 手机号授权code
* @return 手机号或null
*/
public static String getPhoneNumber(String phoneCode) {
try {
Map<String, Object> phoneResult = WechatApiUtil.getPhoneNumberByCode(phoneCode);
if (!(Boolean) phoneResult.get("success")) {
System.err.println("获取手机号失败:" + phoneResult.get("errorMsg"));
return null;
}
Map<String, Object> phoneInfo = (Map<String, Object>) phoneResult.get("phone_info");
if (phoneInfo == null) {
System.err.println("微信API返回的手机号信息为空");
return null;
}
String phoneNumber = (String) phoneInfo.get("phoneNumber");
if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
System.err.println("微信API返回的手机号为空");
return null;
}
System.out.println("成功获取用户手机号:" + phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7));
return phoneNumber;
} catch (Exception e) {
System.err.println("获取用户手机号异常:" + e.getMessage());
return null;
}
}
/**
* 创建或更新用户
*
* @param openid 微信openid
* @param phoneNumber 手机号
* @param usersService 用户服务
* @return 用户对象
* @throws Exception 操作失败时抛出
*/
public static Users createOrUpdateUser(String openid, String phoneNumber, IUsersService usersService) throws Exception {
// 1. 生成用户token
String token = WechatApiUtil.generateUserToken(openid);
if (token == null || token.trim().isEmpty()) {
throw new Exception("生成用户token失败");
}
// 2. 检查手机号是否已存在
Users existingUserByPhone = usersService.selectUsersByPhone(phoneNumber);
if (existingUserByPhone != null) {
// 3. 更新已有用户的openid和token
return updateExistingUser(existingUserByPhone, openid, token, usersService);
} else {
// 4. 创建新用户
return createNewUser(openid, phoneNumber, token, usersService);
}
}
/**
* 更新已有用户信息
*
* @param user 已有用户
* @param openid 微信openid
* @param token 新token
* @param usersService 用户服务
* @return 更新后的用户
* @throws Exception 更新失败时抛出
*/
public static Users updateExistingUser(Users user, String openid, String token, IUsersService usersService) throws Exception {
try {
user.setOpenid(openid);
user.setRememberToken(token);
int updateResult = usersService.updateUsers(user);
if (updateResult <= 0) {
throw new Exception("更新用户信息失败");
}
System.out.println("成功更新用户信息用户ID" + user.getId());
return user;
} catch (Exception e) {
System.err.println("更新用户信息异常:" + e.getMessage());
throw new Exception("更新用户信息失败:" + e.getMessage());
}
}
/**
* 创建新用户
*
* @param openid 微信openid
* @param phoneNumber 手机号
* @param token 用户token
* @param usersService 用户服务
* @return 新创建的用户
* @throws Exception 创建失败时抛出
*/
public static Users createNewUser(String openid, String phoneNumber, String token, IUsersService usersService) throws Exception {
try {
Users newUser = new Users();
newUser.setPhone(phoneNumber);
newUser.setRememberToken(token);
newUser.setName("微信用户");
newUser.setOpenid(openid);
newUser.setAvatar("/default/user_avatar.jpeg");
newUser.setType("1");
newUser.setStatus(1);
newUser.setIsWork(0);
int insertResult = usersService.insertUsers(newUser);
if (insertResult <= 0) {
throw new Exception("创建用户记录失败");
}
System.out.println("成功创建新用户,手机号:" + phoneNumber.substring(0, 3) + "****" + phoneNumber.substring(7));
return newUser;
} catch (Exception e) {
System.err.println("创建新用户异常:" + e.getMessage());
throw new Exception("创建用户失败:" + e.getMessage());
}
}
/**
* 构建成功响应
*
* @param user 用户对象
* @param isNewUser 是否为新用户
* @return 响应结果
*/
public static AjaxResult buildSuccessResponse(Users user, boolean isNewUser) {
try {
// 设置返回字段
user.setRemember_token(user.getRememberToken());
// 构建响应数据
Map<String, Object> responseData = new HashMap<>();
responseData.put("user", user);
responseData.put("isNewUser", isNewUser);
responseData.put("loginTime", System.currentTimeMillis());
responseData.put("message", isNewUser ? "注册成功" : "登录成功");
System.out.println((isNewUser ? "用户注册成功" : "用户登录成功") + "用户ID" + user.getId());
return success(responseData);
} catch (Exception e) {
System.err.println("构建响应数据异常:" + e.getMessage());
return error("登录成功但返回数据异常");
}
}
/**
* 验证用户token并获取用户信息
*
* @param token 用户token
* @param usersService 用户服务
* @return 验证结果
*/
public static Map<String, Object> validateUserToken(String token, IUsersService usersService) {
Map<String, Object> result = new HashMap<>();
try {
if (token == null || token.trim().isEmpty()) {
result.put("valid", false);
result.put("message", "token不能为空");
return result;
}
// 验证token格式
if (!WechatApiUtil.isValidTokenFormat(token.trim())) {
result.put("valid", false);
result.put("message", "token格式无效");
return result;
}
// 查询用户信息
Users user = usersService.selectUsersByRememberToken(token.trim());
if (user == null) {
result.put("valid", false);
result.put("message", "token无效或用户不存在");
return result;
}
// 检查用户状态
if (user.getStatus() == null || user.getStatus() != 1) {
result.put("valid", false);
result.put("message", "用户账号已被禁用");
return result;
}
// 设置返回字段并过滤敏感信息
user.setRemember_token(user.getRememberToken());
result.put("valid", true);
result.put("user", user);
result.put("message", "token验证成功");
} catch (Exception e) {
result.put("valid", false);
result.put("message", "token验证异常" + e.getMessage());
System.err.println("验证用户token异常" + e.getMessage());
}
return result;
}
/**
* 获取并验证请求头中的token
*
* @param authHeader Authorization请求头
* @param tokenHeader token请求头
* @return 提取的token或null
*/
public static String extractToken(String authHeader, String tokenHeader) {
String token = tokenHeader;
// 如果token头为空尝试从Authorization头获取
if (token == null || token.trim().isEmpty()) {
if (authHeader != null && authHeader.startsWith("Bearer ")) {
token = authHeader.substring(7);
}
}
return (token != null && !token.trim().isEmpty()) ? token.trim() : null;
}
/**
* 构建登录失败响应
*
* @param message 失败信息
* @return 失败响应
*/
public static AjaxResult buildFailureResponse(String message) {
return error("登录失败:" + message);
}
/**
* 构建参数错误响应
*
* @param paramName 参数名
* @return 错误响应
*/
public static AjaxResult buildParamErrorResponse(String paramName) {
return error("参数错误:" + paramName + " 不能为空或格式不正确");
}
}

View File

@ -0,0 +1,155 @@
package com.ruoyi.system.ControllerUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import java.util.HashMap;
import java.util.Map;
/**
* 分页工具类
*
* 提供小程序端分页相关的工具方法
* 主要功能
* 1. 构建标准分页响应格式
* 2. 分页参数计算
* 3. 分页URL构建
*
* @author Mr. Zhang Pan
* @date 2025-01-03
* @version 1.0
*/
public class PageUtil {
/**
* 构建小程序端标准分页响应数据
*
* @param tableDataInfo 分页表格数据
* @param currentPage 当前页码
* @param perPage 每页数量
* @return 分页响应数据
*
* 返回格式
* {
* "current_page": 1,
* "data": [...],
* "from": 1,
* "last_page": 1,
* "next_page_url": "?page=2&limit=15",
* "per_page": "15",
* "prev_page_url": null,
* "to": 15,
* "total": 25
* }
*/
public static Map<String, Object> buildPageResponse(TableDataInfo tableDataInfo, int currentPage, int perPage) {
Map<String, Object> pageData = new HashMap<>();
// 计算分页信息
long total = tableDataInfo.getTotal();
int lastPage = (int) Math.ceil((double) total / perPage);
int from = total > 0 ? (currentPage - 1) * perPage + 1 : 0;
int to = (int) Math.min(currentPage * perPage, total);
// 构建分页URL这里简化处理实际项目中可以根据需要构建完整URL
String nextPageUrl = (currentPage < lastPage) ? "?page=" + (currentPage + 1) + "&limit=" + perPage : null;
String prevPageUrl = (currentPage > 1) ? "?page=" + (currentPage - 1) + "&limit=" + perPage : null;
// 设置分页数据
pageData.put("current_page", currentPage);
pageData.put("data", tableDataInfo.getRows());
pageData.put("from", from);
pageData.put("last_page", lastPage);
pageData.put("next_page_url", nextPageUrl);
pageData.put("per_page", String.valueOf(perPage));
pageData.put("prev_page_url", prevPageUrl);
pageData.put("to", to);
pageData.put("total", total);
return pageData;
}
/**
* 构建简单的分页响应数据不包含URL
*
* @param tableDataInfo 分页表格数据
* @param currentPage 当前页码
* @param perPage 每页数量
* @return 简单分页响应数据
*/
public static Map<String, Object> buildSimplePageResponse(TableDataInfo tableDataInfo, int currentPage, int perPage) {
Map<String, Object> pageData = new HashMap<>();
// 计算分页信息
long total = tableDataInfo.getTotal();
int lastPage = (int) Math.ceil((double) total / perPage);
int from = total > 0 ? (currentPage - 1) * perPage + 1 : 0;
int to = (int) Math.min(currentPage * perPage, total);
// 设置分页数据不包含URL
pageData.put("current_page", currentPage);
pageData.put("data", tableDataInfo.getRows());
pageData.put("from", from);
pageData.put("last_page", lastPage);
pageData.put("per_page", String.valueOf(perPage));
pageData.put("to", to);
pageData.put("total", total);
return pageData;
}
/**
* 计算总页数
*
* @param total 总记录数
* @param perPage 每页数量
* @return 总页数
*/
public static int calculateTotalPages(long total, int perPage) {
return (int) Math.ceil((double) total / perPage);
}
/**
* 计算偏移量
*
* @param page 页码
* @param limit 每页数量
* @return 偏移量
*/
public static int calculateOffset(int page, int limit) {
return (page - 1) * limit;
}
/**
* 验证分页参数
*
* @param page 页码
* @param limit 每页数量
* @return 验证结果
*/
public static Map<String, Object> validatePageParams(int page, int limit) {
Map<String, Object> result = new HashMap<>();
if (page < 1) {
result.put("valid", false);
result.put("message", "页码不能小于1");
return result;
}
if (limit < 1) {
result.put("valid", false);
result.put("message", "每页数量不能小于1");
return result;
}
if (limit > 100) {
result.put("valid", false);
result.put("message", "每页数量不能超过100");
return result;
}
result.put("valid", true);
result.put("page", page);
result.put("limit", limit);
return result;
}
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.system.domain;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@ -150,6 +152,12 @@ public class Users extends BaseEntity
private BigDecimal marginMax;
private BigDecimal commissionMin;
private BigDecimal commissionMax;
private String remember_token;
private Map<String, Object> order_num;
private Map<String, Object> goods_order_num;
public void setId(Long id)
{
@ -507,6 +515,30 @@ public class Users extends BaseEntity
this.isWork = isWork;
}
public String getRemember_token() {
return remember_token;
}
public void setRemember_token(String remember_token) {
this.remember_token = remember_token;
}
public Map<String, Object> getOrder_num() {
return order_num;
}
public void setOrder_num(Map<String, Object> order_num) {
this.order_num = order_num;
}
public Map<String, Object> getGoods_order_num() {
return goods_order_num;
}
public void setGoods_order_num(Map<String, Object> goods_order_num) {
this.goods_order_num = goods_order_num;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)