1. 意见反馈

2. 客服电话
This commit is contained in:
邱贞招 2024-10-28 10:37:17 +08:00
parent 42799b0e26
commit c6dd7eb02b
12 changed files with 190 additions and 77 deletions

View File

@ -13,6 +13,7 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.device.service.IAsUserService;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -3,17 +3,19 @@ package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.Set;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.device.domain.AsDevice;
import com.ruoyi.device.service.IAsUserService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.controller.common.CaptchaController;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
@ -32,6 +34,8 @@ import com.ruoyi.system.service.ISysMenuService;
@RestController
public class SysLoginController
{
private static final Logger log = LoggerFactory.getLogger(SysLoginController.class);
@Autowired
private SysLoginService loginService;
@ -123,7 +127,7 @@ public class SysLoginController
String phone = loginBody.getPhone();
AsUser user = asUserService.selectUserByPhone(phone);
// 生成令牌
String token = loginService.appCodeLogin(user.getUserName(), loginBody.getPhoneCode(), loginBody.getUuid());
String token = loginService.appCodeLogin(user.getUserName(), loginBody.getPhoneCode(),loginBody.getPassword(), loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
@ -152,4 +156,17 @@ public class SysLoginController
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* app忘记密码
*/
// @Log(title = "app忘记密码", businessType = BusinessType.UPDATE)
@PutMapping("/forgetAppPwd")
public AjaxResult forgetAppPwd(String phone,String phoneCode, String newPassword,String uuid)
{
log.info("【app忘记密码】请求参数phone:{},phoneCode:{},newPassword:{}",phone,phoneCode,newPassword);
return AjaxResult.success(loginService.forgetAppPwd(phone,phoneCode,newPassword,uuid));
}
}

View File

@ -194,6 +194,15 @@ public class Constants
* 用户类型 2为 app用户
* */
public static final String USER_TYPE_APP = "01";
/**
* 用户类型 3为 app用户(短信登录)
* */
public static final String USER_TYPE_MSG = "03";
/**
* 用户类型 3为 app用户(密码登录)
* */
public static final String USER_TYPE_PASSWORD = "04";
}

View File

@ -113,7 +113,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login","/wxlogin", "/register", "/captchaImage","/common/receive","/appCaptcha","/appCodeLogin","/app/**","/common/upload","/loginByopenid","/weather").permitAll()
.antMatchers("/login","/wxlogin", "/register", "/captchaImage","/common/receive","/appCaptcha","/appCodeLogin","/app/**",
"/forgetAppPwd","/common/upload","/loginByopenid","/weather").permitAll()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

View File

@ -1,22 +1,32 @@
package com.ruoyi.framework.web.service;
import javax.annotation.Resource;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.*;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.wx.AccessTokenUtil;
import com.ruoyi.common.utils.wx.vo.AccessToken;
import com.ruoyi.device.domain.vo.WeChatMiniAuthorizeVo;
import com.ruoyi.device.service.IAsUserService;
import me.chanjar.weixin.common.error.WxErrorException;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -25,27 +35,8 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.BlackListException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import javax.annotation.Resource;
/**
* 登录校验方法
@ -228,20 +219,35 @@ public class SysLoginService
*
* @param username 手机号
* @param code 验证码
* @param password 密码
* @param uuid uuid
* @return 结果
*/
public String appCodeLogin(String username, String code, String uuid) {
if(!"8888".equals(code)){
validateCaptcha(username, code, uuid); //校验验证码
public String appCodeLogin(String username, String code, String password, String uuid) {
if(StrUtil.isBlank(code)){
// 登录前置校验
loginPreCheck(username, password);
}else{
if(!"8888".equals(code)){
validateCaptcha(username, code, uuid); //校验验证码
}
}
Authentication authentication = null; // 用户验证
try {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, Constants.CUSTOM_LOGIN_SMS);
// 用户名和密码等信息保存在一个上下文中只要是同一线程等会就能拿到用户名和密码也就是能在loadUserByUsername(String username)方法中进行密码验证等
AuthenticationContextHolder.setContext(authenticationToken);
// 把用户类型放在上下文中的details属性中在UserDetailsServiceImpl.loadUserByUsername中获取
authenticationToken.setDetails(Constants.USER_TYPE_APP);
UsernamePasswordAuthenticationToken authenticationToken;
if(StrUtil.isBlank(code)){
authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
// 用户名和密码等信息保存在一个上下文中只要是同一线程等会就能拿到用户名和密码也就是能在loadUserByUsername(String username)方法中进行密码验证等
AuthenticationContextHolder.setContext(authenticationToken);
// 把用户类型放在上下文中的details属性中在UserDetailsServiceImpl.loadUserByUsername中获取
authenticationToken.setDetails(Constants.USER_TYPE_PASSWORD);
}else{
authenticationToken = new UsernamePasswordAuthenticationToken(username, Constants.CUSTOM_LOGIN_SMS);
// 用户名和密码等信息保存在一个上下文中只要是同一线程等会就能拿到用户名和密码也就是能在loadUserByUsername(String username)方法中进行密码验证等
AuthenticationContextHolder.setContext(authenticationToken);
// 把用户类型放在上下文中的details属性中在UserDetailsServiceImpl.loadUserByUsername中获取
authenticationToken.setDetails(Constants.USER_TYPE_MSG);
}
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);
}
@ -369,5 +375,16 @@ public class SysLoginService
return openId;
}
/**
* 忘记密码
*/
public int forgetAppPwd(String phone, String phoneCode, String newPassword,String uuid) {
AsUser user = asUserService.selectUserByPhone(phone);
validateCaptcha(phone, phoneCode, uuid); //校验验证码
newPassword = SecurityUtils.encryptPassword(newPassword);
asUserService.updateUserPwd(user.getUserId(), newPassword);
return 1;
}
}

View File

@ -21,7 +21,7 @@ import com.ruoyi.framework.security.context.AuthenticationContextHolder;
/**
* 登录密码方法
*
*
* @author ruoyi
*/
@Component
@ -38,7 +38,7 @@ public class SysPasswordService
/**
* 登录账户密码错误次数缓存键名
*
*
* @param username 用户名
* @return 缓存键key
*/
@ -81,11 +81,47 @@ public class SysPasswordService
}
}
public void validate2(AsUser user)
{
Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
String username = usernamePasswordAuthenticationToken.getName();
String password = usernamePasswordAuthenticationToken.getCredentials().toString();
Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
if (retryCount == null)
{
retryCount = 0;
}
if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
{
throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
}
if (!matches2(user, password))
{
retryCount = retryCount + 1;
redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
throw new UserPasswordNotMatchException();
}
else
{
clearLoginRecordCache(username);
}
}
public boolean matches(SysUser user, String rawPassword)
{
return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
}
public boolean matches2(AsUser user, String rawPassword)
{
return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
}
public void clearLoginRecordCache(String loginName)
{
if (redisCache.hasKey(getCacheKey(loginName)))

View File

@ -1,5 +1,6 @@
package com.ruoyi.framework.web.service;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysUser;
@ -7,6 +8,7 @@ import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.device.service.IAsUserService;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
@ -37,7 +39,7 @@ public class UserDetailsServiceImpl implements UserDetailsService
@Resource
private IAsUserService asUserService;
@Autowired
private SysPasswordService passwordService;
@ -54,21 +56,7 @@ public class UserDetailsServiceImpl implements UserDetailsService
if(Constants.USER_TYPE_PC.equals(userType)){
// PC用户登录
SysUser user = userService.selectUserByUserName(username);
if (StringUtils.isNull(user))
{
log.info("登录用户:{} 不存在.", username);
throw new ServiceException(MessageUtils.message("user.not.exists"));
}
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException(MessageUtils.message("user.password.delete"));
}
else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}
verifyUser(username, user);
passwordService.validate(user);
@ -76,22 +64,16 @@ public class UserDetailsServiceImpl implements UserDetailsService
}else {
// app用户登录
AsUser user = asUserService.selectUserByUserName(username);
if (StringUtils.isNull(user))
{
log.info("登录用户:{} 不存在.", username);
throw new ServiceException(MessageUtils.message("user.not.exists"));
verifyUser(username, user);
if(Constants.USER_TYPE_PASSWORD.equals(userType)){
if(StrUtil.isBlank(user.getPassword())){
String password = authentication.getCredentials().toString();
String newPassword = SecurityUtils.encryptPassword(password);
asUserService.updateUserPwd(user.getUserId(), newPassword);
}else{
passwordService.validate2(user);
}
}
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException(MessageUtils.message("user.password.delete"));
}
else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}
return createLoginUser(user);
}
@ -110,4 +92,32 @@ public class UserDetailsServiceImpl implements UserDetailsService
{
return new LoginUser(user.getUserId(), user);
}
/** 校验用户*/
private void verifyUser(String username, SysUser user) {
if (StringUtils.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new ServiceException(MessageUtils.message("user.not.exists"));
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException(MessageUtils.message("user.password.delete"));
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}
}
/** 校验用户*/
private void verifyUser(String username, AsUser user) {
if (StringUtils.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new ServiceException(MessageUtils.message("user.not.exists"));
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException(MessageUtils.message("user.password.delete"));
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}
}
}

View File

@ -135,4 +135,9 @@ public interface AsUserMapper
public AsUser selectUserByPhone(String phone);
AsUser selectUserByWxopenid(String openid);
/**
* 更新用户密码
*/
int updateUserPwd(@Param("userId") Long userId, @Param("password") String password);
}

View File

@ -196,4 +196,9 @@ public interface IAsUserService
* @return 用户对象信息
*/
AsUser selectUserByWxopenid(String openid);
/**
* 修改用户密码
*/
void updateUserPwd(Long userId, String newPassword);
}

View File

@ -62,7 +62,7 @@ public class AsArticleServiceImpl implements IAsArticleService
* 新增文章
*
* @param asArticle 文章
* @return 结果
* @return 结果
*/
@Override
public int insertAsArticle(AsArticle asArticle)

View File

@ -561,4 +561,12 @@ public class AsUserServiceImpl implements IAsUserService
}
}
}
/**
* 更新用户密码
*/
@Override
public void updateUserPwd(Long userId, String newPassword) {
asUserMapper.updateUserPwd(userId, newPassword);
}
}

View File

@ -186,4 +186,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</delete>
<update id="updateUserPwd">
update as_user set password = #{password} where user_id = #{userId}
</update>
</mapper>