diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 968969d..b66a14c 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -16,7 +16,6 @@ - org.springframework.boot @@ -105,6 +104,15 @@ org.springframework.boot spring-boot-maven-plugin ${spring-boot.version} + + + + + org.springframework + springloaded + 1.2.8.RELEASE + + true diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java index 78c44e3..edcc692 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java @@ -1,6 +1,7 @@ package com.ruoyi.web.controller.system; import cn.dev33.satoken.annotation.SaIgnore; +import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.entity.SysMenu; @@ -19,6 +20,7 @@ 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.multipart.MultipartFile; import javax.validation.constraints.NotBlank; import java.util.HashMap; @@ -38,6 +40,7 @@ public class SysLoginController { private final SysLoginService loginService; private final ISysMenuService menuService; private final ISysUserService userService; + private final RuoYiConfig config; /** * 登录方法 @@ -47,13 +50,10 @@ public class SysLoginController { */ @SaIgnore @PostMapping("/login") - public R> login(@Validated @RequestBody LoginBody loginBody) { - Map ajax = new HashMap<>(); - // 生成令牌 + public R login(@Validated @RequestBody LoginBody loginBody) { String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid()); - ajax.put(Constants.TOKEN, token); - return R.ok(ajax); + return R.map().put(Constants.TOKEN, token); } /** @@ -64,12 +64,9 @@ public class SysLoginController { */ @SaIgnore @PostMapping("/smsLogin") - public R> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) { - Map ajax = new HashMap<>(); - // 生成令牌 + public R smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) { String token = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode()); - ajax.put(Constants.TOKEN, token); - return R.ok(ajax); + return R.map().put(Constants.TOKEN,token); } /** @@ -80,12 +77,41 @@ public class SysLoginController { */ @SaIgnore @PostMapping("/xcxLogin") - public R> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { - Map ajax = new HashMap<>(); - // 生成令牌 + public R xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { String token = loginService.xcxLogin(xcxCode); - ajax.put(Constants.TOKEN, token); - return R.ok(ajax); + return R.map().put(Constants.TOKEN,token); + } + + + @SaIgnore + @PostMapping("/openid") + public R xcxOpenid(@NotBlank(message = "{xcx.code.not.blank}") String openid) { + if(!config.getDev()){ + throw new RuntimeException("未开发环境不允许直接使用openid登录"); + } + String token = loginService.xcxLoginByOpenId(openid); + return R.map().put(Constants.TOKEN,token); + } + + + @SaIgnore + @PostMapping("/xcxRegLogin") + public R xcxRegLogin(@NotBlank(message = "{xcx.code.not.blank}") String code, + MultipartFile avatar, + @NotBlank(message = "{not.null}") String nickname) { + String token = loginService.xcxRegLogin(code,avatar,nickname); + return R.map().put(Constants.TOKEN,token); + } + + + @SaIgnore + @PostMapping("/xcxRegLoginByOpenid") + public R xcxRegLoginByOpenid(String openid, MultipartFile avatar, String nickname) { + if(!config.getDev()){ + throw new RuntimeException("未开发环境不允许直接使用openid登录"); + } + String token = loginService.xcxRegLoginByOpenid(openid,avatar,nickname); + return R.map().put(Constants.TOKEN,token); } /** @@ -104,14 +130,12 @@ public class SysLoginController { * @return 用户信息 */ @GetMapping("getInfo") - public R> getInfo() { + public R getInfo() { LoginUser loginUser = LoginHelper.getLoginUser(); SysUser user = userService.selectUserById(loginUser.getUserId()); - Map ajax = new HashMap<>(); - ajax.put("user", user); - ajax.put("roles", loginUser.getRolePermission()); - ajax.put("permissions", loginUser.getMenuPermission()); - return R.ok(ajax); + return R.map().put("user", user) + .put("roles", loginUser.getRolePermission()) + .put("permissions", loginUser.getMenuPermission()); } /** diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index d0c25a1..b3de9e3 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -14,6 +14,21 @@ ruoyi: addressEnabled: true # 缓存懒加载 cacheLazy: false + # 小程序的用户默认设置 + default-user: + # 所在单位 + dept-id: 101 + # 用户类型 + user-type: app_user + # 帐号状态(0正常 1停用) + status: 0 + # 用户组 + role-ids: + - 2 + # 岗位组 + post-ids: + - 4 + wx: miniapp: @@ -27,9 +42,9 @@ wx: captcha: # 页面 <参数设置> 可开启关闭 验证码校验 # 验证码类型 math 数组计算 char 字符验证 - type: MATH + type: char # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 - category: CIRCLE + category: shear # 数字验证码位数 numberLength: 1 # 字符验证码长度 @@ -108,6 +123,9 @@ spring: deserialization: # 允许对象忽略json中不存在的属性 fail_on_unknown_properties: false + # 不输出null + default-property-inclusion: non_null + # Sa-Token配置 sa-token: @@ -128,7 +146,7 @@ sa-token: # token前缀 token-prefix: "Bearer" # jwt秘钥 - jwt-secret-key: abcdefghijklmnopqrstuvwxyz + jwt-secret-key: a1b2c3defg8hi9jkl46mnop3qrstu5vwxyz # security配置 security: diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java index 4caa6ca..c63b4ba 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java @@ -1,5 +1,8 @@ package com.ruoyi.common.config; +import com.baomidou.mybatisplus.annotation.TableField; +import com.ruoyi.common.enums.UserStatus; +import com.ruoyi.common.enums.UserType; import lombok.Data; import lombok.Getter; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -54,4 +57,27 @@ public class RuoYiConfig { RuoYiConfig.addressEnabled = addressEnabled; } + private DefaultUser defaultUser = new DefaultUser(); + + @Data + public class DefaultUser { + private Long deptId = 100L; + + private String userType = UserType.APP_USER.getUserType(); + /** + * 帐号状态(0正常 1停用) + */ + private String status = UserStatus.OK.getCode(); + /** + * 角色组 + */ + private Long[] roleIds = {2L}; + + /** + * 岗位组 + */ + private Long[] postIds = {4L}; + + } + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java index 97e1ea5..85042a0 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java @@ -126,7 +126,9 @@ public class R implements Serializable { public static R> map(){ R> r = new R<>(); - r.setData(new HashMap<>()); + r.setCode(SUCCESS); + r.setMsg("操作成功"); + r.setData(new HashMap<>(10)); return r; } @@ -142,7 +144,9 @@ public class R implements Serializable { public static R> list(){ R> r = new R<>(); - r.setData(new ArrayList<>()); + r.setData(new ArrayList<>(10)); + r.setCode(SUCCESS); + r.setMsg("操作成功"); return r; } @@ -155,4 +159,5 @@ public class R implements Serializable { throw new RuntimeException("data does not belong to List"); } } + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java index d9139c5..08c3444 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java @@ -41,6 +41,8 @@ public class SysUser extends BaseEntity { */ private Long deptId; + + private String openid; /** * 用户账号 */ diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java index b284216..224371d 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java @@ -20,7 +20,7 @@ public class CaptchaConfig { private static final int WIDTH = 160; private static final int HEIGHT = 60; - private static final Color BACKGROUND = Color.PINK; + private static final Color BACKGROUND = Color.white; private static final Font FONT = new Font("Arial", Font.BOLD, 48); /** diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/satoken/service/SaPermissionImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/satoken/service/SaPermissionImpl.java index 632cc71..6d620d5 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/satoken/service/SaPermissionImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/satoken/service/SaPermissionImpl.java @@ -22,12 +22,12 @@ public class SaPermissionImpl implements StpInterface { public List getPermissionList(Object loginId, String loginType) { LoginUser loginUser = LoginHelper.getLoginUser(); UserType userType = UserType.getUserType(loginUser.getUserType()); - if (userType == UserType.SYS_USER) { +// if (userType == UserType.SYS_USER) { return new ArrayList<>(loginUser.getMenuPermission()); - } else if (userType == UserType.APP_USER) { - // 其他端 自行根据业务编写 - } - return new ArrayList<>(); +// } else if (userType == UserType.APP_USER) { +// // 其他端 自行根据业务编写 +// } +// return new ArrayList<>(); } /** @@ -37,11 +37,11 @@ public class SaPermissionImpl implements StpInterface { public List getRoleList(Object loginId, String loginType) { LoginUser loginUser = LoginHelper.getLoginUser(); UserType userType = UserType.getUserType(loginUser.getUserType()); - if (userType == UserType.SYS_USER) { +// if (userType == UserType.SYS_USER) { return new ArrayList<>(loginUser.getRolePermission()); - } else if (userType == UserType.APP_USER) { - // 其他端 自行根据业务编写 - } - return new ArrayList<>(); +// } else if (userType == UserType.APP_USER) { +// // 其他端 自行根据业务编写 +// } +// return new ArrayList<>(); } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index cfa6e16..40dbd07 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -56,6 +56,13 @@ public interface ISysUserService { */ SysUser selectUserByPhonenumber(String phonenumber); + + /** + * 根据openid获取用户 + * @param openid + * @return + */ + SysUser selectUserByOpenid(String openid); /** * 通过用户ID查询用户 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java index 3c29b85..cd9d13d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java @@ -1,11 +1,16 @@ package com.ruoyi.system.service; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.event.LogininforEvent; @@ -16,6 +21,8 @@ import com.ruoyi.common.core.domain.model.XcxLoginUser; import com.ruoyi.common.enums.DeviceType; import com.ruoyi.common.enums.LoginType; import com.ruoyi.common.enums.UserStatus; +import com.ruoyi.common.enums.UserType; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.CaptchaExpireException; import com.ruoyi.common.exception.user.UserException; @@ -29,8 +36,10 @@ import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.system.mapper.SysUserMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.time.Duration; @@ -48,9 +57,20 @@ import java.util.function.Supplier; public class SysLoginService { private final SysUserMapper userMapper; + + private final ISysUserService userService; + private final ISysConfigService configService; private final SysPermissionService permissionService; + private final IdentifierGenerator id; + + private final ISysOssService ossService; + + private final WxMaService wxMaService; + + private final RuoYiConfig config; + @Value("${user.password.maxRetryCount}") private Integer maxRetryCount; @@ -100,19 +120,72 @@ public class SysLoginService { return StpUtil.getTokenValue(); } + public String xcxRegLogin(String xcxCode, MultipartFile avatar,String nickname) { + WxMaJscode2SessionResult session = null; + try { + session = wxMaService.getUserService().getSessionInfo(xcxCode); + } catch (WxErrorException e) { + throw new RuntimeException(e); + } + String openid = session.getOpenid(); + return xcxRegLoginByOpenid(openid,avatar,nickname); + } + + public String xcxRegLoginByOpenid(String openid, MultipartFile avatar,String nickname) { + LambdaQueryWrapper q = Wrappers.lambdaQuery(); + if(userMapper.selectCount(q.eq(SysUser::getOpenid,openid))>0){ + throw new ServiceException("用户已经注册"); + } + String url = null; + try { + url = ossService.uploadImgs(avatar,"avatar",400,400,null).getUrl(); + }catch (Exception e){ + log.debug("保存头像失败",e); +// throw new RuntimeException("保存头像失败",e); + } + + SysUser user = new SysUser(); + //设置默认值 + BeanUtil.copyProperties(config.getDefaultUser(),user); + user.setOpenid(openid); + user.setAvatar(url); + user.setUserName("_"+new StringBuffer(Long.toString(id.nextId(null).longValue(),36)).reverse().toString()); + user.setNickName(nickname); + userService.insertUser(user); + return xcxLoginByOpenId(openid); + } + public String xcxLogin(String xcxCode) { - // xcxCode 为 小程序调用 wx.login 授权后获取 - // todo 以下自行实现 - // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid - String openid = ""; + WxMaJscode2SessionResult session = null; + try { + session = wxMaService.getUserService().getSessionInfo(xcxCode); + } catch (WxErrorException e) { + throw new RuntimeException(e); + } + String openid = session.getOpenid(); + return xcxLoginByOpenId(openid); + } + + + /** + * 该方法为开发时测试提供直接登录的方法 + * @param openid + * @return + */ + public String xcxLoginByOpenId(String openid) { SysUser user = loadUserByOpenid(openid); - // 此处可根据登录用户的数据不同 自行创建 loginUser XcxLoginUser loginUser = new XcxLoginUser(); loginUser.setUserId(user.getUserId()); + loginUser.setDeptId(user.getDeptId()); loginUser.setUsername(user.getUserName()); loginUser.setUserType(user.getUserType()); + loginUser.setMenuPermission(permissionService.getMenuPermission(user)); + loginUser.setRolePermission(permissionService.getRolePermission(user)); + loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); + List roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); + loginUser.setRoles(roles); loginUser.setOpenid(openid); // 生成token LoginHelper.loginByDevice(loginUser, DeviceType.XCX); @@ -214,14 +287,17 @@ public class SysLoginService { private SysUser loadUserByOpenid(String openid) { // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 + // oKSa06DQ-6mA-1qrP9CW9uRzgLgY // todo 自行实现 userService.selectUserByOpenid(openid); - SysUser user = new SysUser(); + SysUser user = userService.selectUserByOpenid(openid); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", openid); // todo 用户不存在 业务逻辑自行实现 + throw new ServiceException("用户未注册"); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", openid); // todo 用户已被停用 业务逻辑自行实现 + throw new ServiceException("用户已被停用"); } return user; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index b410587..a050607 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -151,6 +151,11 @@ public class SysUserServiceImpl implements ISysUserService, UserService { return baseMapper.selectUserByPhonenumber(phonenumber); } + @Override + public SysUser selectUserByOpenid(String openid) { + return baseMapper.selectOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getOpenid,openid)); + } + /** * 通过用户ID查询用户 *