Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/bpm-back

This commit is contained in:
YunaiV
2022-05-26 19:19:48 +08:00
406 changed files with 24646 additions and 16109 deletions

View File

@@ -29,13 +29,6 @@
<optional>true</optional>
</dependency>
<!-- 用户信息 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO;
import javax.validation.Valid;
/**
* OAuth2.0 Token API 接口
*
* @author 芋道源码
*/
public interface OAuth2TokenApi {
/**
* 创建访问令牌
*
* @param reqDTO 访问令牌的创建信息
* @return 访问令牌的信息
*/
OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO);
/**
* 校验访问令牌
*
* @param accessToken 访问令牌
* @return 访问令牌的信息
*/
OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken);
/**
* 移除访问令牌
*
* @param accessToken 访问令牌
* @return 访问令牌的信息
*/
OAuth2AccessTokenRespDTO removeAccessToken(String accessToken);
/**
* 刷新访问令牌
*
* @param refreshToken 刷新令牌
* @param clientId 客户端编号
* @return 访问令牌的信息
*/
OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId);
}

View File

@@ -1,56 +0,0 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 在线用户 Session API 接口
*
* @author 芋道源码
*/
public interface UserSessionApi {
/**
* 创建在线用户 Session
*
* @param loginUser 登录用户
* @param userIp 用户 IP
* @param userAgent 用户 UA
* @return Session 编号
*/
String createUserSession(@NotNull(message = "登录用户不能为空") LoginUser loginUser, String userIp, String userAgent);
/**
* 刷新在线用户 Session 的更新时间
*
* @param sessionId Session 编号
* @param loginUser 登录用户
*/
void refreshUserSession(@NotEmpty(message = "Session编号不能为空") String sessionId,
@NotNull(message = "登录用户不能为空") LoginUser loginUser);
/**
* 删除在线用户 Session
*
* @param sessionId Session 编号
*/
void deleteUserSession(String sessionId);
/**
* 获得 Session 编号对应的在线用户
*
* @param sessionId Session 编号
* @return 在线用户
*/
LoginUser getLoginUser(String sessionId);
/**
* 获得 Session 超时时间,单位:毫秒
*
* @return 超时时间
*/
Long getSessionTimeoutMillis();
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.api.auth.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* OAuth2.0 访问令牌的校验 Response DTO
*
* @author 芋道源码
*/
@Data
public class OAuth2AccessTokenCheckRespDTO implements Serializable {
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 租户编号
*/
private Long tenantId;
/**
* 授权范围的数组
*/
private List<String> scopes;
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.api.auth.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
* OAuth2.0 访问令牌创建 Request DTO
*
* @author 芋道源码
*/
@Data
public class OAuth2AccessTokenCreateReqDTO implements Serializable {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
@InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}")
private Integer userType;
/**
* 客户端编号
*/
@NotNull(message = "客户端编号不能为空")
private String clientId;
/**
* 授权范围
*/
private List<String> scopes;
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.api.auth.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* OAuth2.0 访问令牌的信息 Response DTO
*
* @author 芋道源码
*/
@Data
@Accessors(chain = true)
public class OAuth2AccessTokenRespDTO implements Serializable {
/**
* 访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 过期时间
*/
private Date expiresTime;
}

View File

@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import java.util.Collection;
import java.util.Set;
@@ -18,4 +20,30 @@ public interface PermissionApi {
*/
Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds);
/**
* 判断是否有权限,任一一个即可
*
* @param userId 用户编号
* @param permissions 权限
* @return 是否
*/
boolean hasAnyPermissions(Long userId, String... permissions);
/**
* 判断是否有角色,任一一个即可
*
* @param userId 用户编号
* @param roles 角色数组
* @return 是否
*/
boolean hasAnyRoles(Long userId, String... roles);
/**
* 获得登陆用户的部门数据权限
*
* @param userId 用户编号
* @return 部门数据权限
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.api.permission.dto;
import lombok.Data;
import java.util.HashSet;
import java.util.Set;
/**
* 部门的数据权限 Response DTO
*
* @author 芋道源码
*/
@Data
public class DeptDataPermissionRespDTO {
/**
* 是否可查看全部数据
*/
private Boolean all;
/**
* 是否可查看自己的数据
*/
private Boolean self;
/**
* 可查看的部门编号数组
*/
private Set<Long> deptIds;
public DeptDataPermissionRespDTO() {
this.all = false;
this.self = false;
this.deptIds = new HashSet<>();
}
}

View File

@@ -12,11 +12,11 @@ public interface ErrorCodeConstants {
// ========== AUTH 模块 1002000000 ==========
ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确");
ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用");
ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登录失败的兜底,未知原因
ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在");
ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确");
ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定");
ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1002000006, "Token 已经过期");
ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1002000007, "手机号不存在");
// ========== 菜单模块 1002001000 ==========
ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1002001000, "已经存在该名字的菜单");
@@ -119,8 +119,27 @@ public interface ErrorCodeConstants {
ErrorCode SOCIAL_USER_UNBIND_NOT_SELF = new ErrorCode(1002018001, "社交解绑失败,非当前用户绑定");
ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1002018002, "社交授权失败,找不到对应的用户");
// ========== 系统感词 1002019000 =========
// ========== 系统感词 1002019000 =========
ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1002019000, "系统敏感词在所有标签中都不存在");
ErrorCode SENSITIVE_WORD_EXISTS = new ErrorCode(1002019001, "系统敏感词已在标签中存在");
// ========== OAuth2 客户端 1002020000 =========
ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1002020000, "OAuth2 客户端不存在");
ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1002020001, "OAuth2 客户端编号已存在");
ErrorCode OAUTH2_CLIENT_DISABLE = new ErrorCode(1002020002, "OAuth2 客户端已禁用");
ErrorCode OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS = new ErrorCode(1002020003, "不支持该授权类型");
ErrorCode OAUTH2_CLIENT_SCOPE_OVER = new ErrorCode(1002020004, "授权范围过大");
ErrorCode OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH = new ErrorCode(1002020005, "无效 redirect_uri: {}");
ErrorCode OAUTH2_CLIENT_CLIENT_SECRET_ERROR = new ErrorCode(1002020006, "无效 client_secret: {}");
// ========== OAuth2 授权 1002021000 =========
ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1002021000, "client_id 不匹配");
ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1002021001, "redirect_uri 不匹配");
ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1002021002, "state 不匹配");
ErrorCode OAUTH2_GRANT_CODE_NOT_EXISTS = new ErrorCode(1002021003, "code 不存在");
// ========== OAuth2 授权 1002022000 =========
ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1002022000, "code 不存在");
ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1002022000, "code 已过期");
}

View File

@@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.system.enums.auth;
/**
* OAuth2.0 客户端的通用枚举
*
* @author 芋道源码
*/
public interface OAuth2ClientConstants {
String CLIENT_ID_DEFAULT = "default";
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.enums.auth;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* OAuth2 授权类型(模式)的枚举
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum OAuth2GrantTypeEnum {
PASSWORD("password"), // 密码模式
AUTHORIZATION_CODE("authorization_code"), // 授权码模式
IMPLICIT("implicit"), // 简化模式
CLIENT_CREDENTIALS("client_credentials"), // 客户端模式
REFRESH_TOKEN("refresh_token"), // 刷新模式
;
private final String grantType;
public static OAuth2GrantTypeEnum getByGranType(String grantType) {
return ArrayUtil.firstMatch(o -> o.getGrantType().equals(grantType), values());
}
}

View File

@@ -12,12 +12,10 @@ public enum LoginLogTypeEnum {
LOGIN_USERNAME(100), // 使用账号登录
LOGIN_SOCIAL(101), // 使用社交登录
LOGIN_MOCK(102), // 使用 Mock 登录
LOGIN_MOBILE(103), // 使用手机登陆
LOGIN_SMS(104), // 使用短信登陆
LOGOUT_SELF(200), // 自己主动登出
LOGOUT_TIMEOUT(201), // 超时登出
LOGOUT_DELETE(202), // 强制退出
;

View File

@@ -18,9 +18,9 @@ public enum SmsSceneEnum implements IntArrayValuable {
MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"),
MEMBER_UPDATE_MOBILE(2, "user-sms-reset-password", "会员用户 - 修改手机"),
MEMBER_FORGET_PASSWORD(3, "user-sms-update-mobile", "会员用户 - 忘记密码");
MEMBER_FORGET_PASSWORD(3, "user-sms-update-mobile", "会员用户 - 忘记密码"),
// 如果未来希望管理后台支持手机验证码登陆,可以通过添加 ADMIN_MEMBER_LOGIN 枚举
ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SmsSceneEnum::getScene).toArray();

View File

@@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* OAuth2.0 Token API 实现类
*
* @author 芋道源码
*/
@Service
public class OAuth2TokenApiImpl implements OAuth2TokenApi {
@Resource
private OAuth2TokenService oauth2TokenService;
@Override
public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());
return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO);
}
@Override
public OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken) {
return OAuth2TokenConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken));
}
@Override
public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken);
return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO);
}
@Override
public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId);
return OAuth2TokenConvert.INSTANCE.convert2(accessTokenDO);
}
}

View File

@@ -1,47 +0,0 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 在线用户 Session API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class UserSessionApiImpl implements UserSessionApi {
@Resource
private UserSessionService userSessionService;
@Override
public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
return userSessionService.createUserSession(loginUser, userIp, userAgent);
}
@Override
public void refreshUserSession(String sessionId, LoginUser loginUser) {
userSessionService.refreshUserSession(sessionId, loginUser);
}
@Override
public void deleteUserSession(String sessionId) {
userSessionService.deleteUserSession(sessionId);
}
@Override
public LoginUser getLoginUser(String sessionId) {
return userSessionService.getLoginUser(sessionId);
}
@Override
public Long getSessionTimeoutMillis() {
return userSessionService.getSessionTimeoutMillis();
}
}

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import org.springframework.stereotype.Service;
@@ -23,4 +24,19 @@ public class PermissionApiImpl implements PermissionApi {
return permissionService.getUserRoleIdListByRoleIds(roleIds);
}
@Override
public boolean hasAnyPermissions(Long userId, String... permissions) {
return permissionService.hasAnyPermissions(userId, permissions);
}
@Override
public boolean hasAnyRoles(Long userId, String... roles) {
return permissionService.hasAnyRoles(userId, roles);
}
@Override
public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
return permissionService.getDeptDataPermission(userId);
}
}

View File

@@ -1,5 +1,5 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/system/login
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
@@ -11,7 +11,7 @@ tenant-id: {{adminTenentId}}
}
### 请求 /login 接口 => 成功(无验证码)
POST {{baseUrl}}/system/login
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
@@ -21,7 +21,7 @@ tenant-id: {{adminTenentId}}
}
### 请求 /get-permission-info 接口 => 成功
GET {{baseUrl}}/system/get-permission-info
GET {{baseUrl}}/system/auth/get-permission-info
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@@ -1,15 +1,17 @@
package cn.iocoder.yudao.module.system.controller.admin.auth;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
@@ -25,18 +27,19 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserRoleIds;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;
import static java.util.Collections.singleton;
@Api(tags = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth") // 暂时不跟 /auth 结尾
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {
@@ -52,13 +55,33 @@ public class AuthController {
@Resource
private SocialUserService socialUserService;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/login")
@ApiOperation("使用账号密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
String token = authService.login(reqVO, getClientIP(), getUserAgent());
// 返回结果
return success(AuthLoginRespVO.builder().token(token).build());
return success(authService.login(reqVO));
}
@PostMapping("/logout")
@ApiOperation("登出系统")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> logout(HttpServletRequest request) {
String token = obtainAuthorization(request, securityProperties.getTokenHeader());
if (StrUtil.isNotBlank(token)) {
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
}
return success(true);
}
@PostMapping("/refresh-token")
@ApiOperation("刷新令牌")
@ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class)
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
return success(authService.refreshToken(refreshToken));
}
@GetMapping("/get-permission-info")
@@ -70,12 +93,12 @@ public class AuthController {
return null;
}
// 获得角色列表
List<RoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds());
Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
List<RoleDO> roleList = roleService.getRolesFromCache(roleIds);
// 获得菜单列表
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
// 拼接结果返回
return success(AuthConvert.INSTANCE.convert(user, roleList, menuList));
}
@@ -83,15 +106,33 @@ public class AuthController {
@GetMapping("/list-menus")
@ApiOperation("获得登录用户的菜单列表")
public CommonResult<List<AuthMenuRespVO>> getMenus() {
// 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
// 获得用户拥有的菜单列表
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
// 转换成 Tree 结构返回
return success(AuthConvert.INSTANCE.buildMenuTree(menuList));
}
// ========== 短信登录相关 ==========
@PostMapping("/sms-login")
@ApiOperation("使用短信验证码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
return success(authService.smsLogin(reqVO));
}
@PostMapping("/send-sms-code")
@ApiOperation(value = "发送手机验证码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
authService.sendSmsCode(reqVO);
return success(true);
}
// ========== 社交登录相关 ==========
@GetMapping("/social-auth-redirect")
@@ -109,18 +150,14 @@ public class AuthController {
@ApiOperation("社交快捷登录,使用 code 授权码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) {
String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent());
// 返回结果
return success(AuthLoginRespVO.builder().token(token).build());
return success(authService.socialQuickLogin(reqVO));
}
@PostMapping("/social-bind-login")
@ApiOperation("社交绑定登录,使用 code 授权码 + 账号密码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) {
String token = authService.socialBindLogin(reqVO, getClientIP(), getUserAgent());
// 返回结果
return success(AuthLoginRespVO.builder().token(token).build());
return success(authService.socialBindLogin(reqVO));
}
}

View File

@@ -1,80 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.auth;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
import cn.iocoder.yudao.module.system.convert.auth.UserSessionConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Api(tags = "管理后台 - 用户 Session")
@RestController
@RequestMapping("/system/user-session")
public class UserSessionController {
@Resource
private UserSessionService userSessionService;
@Resource
private AdminUserService userService;
@Resource
private DeptService deptService;
@GetMapping("/page")
@ApiOperation("获得 Session 分页列表")
@PreAuthorize("@ss.hasPermission('system:user-session:page')")
public CommonResult<PageResult<UserSessionPageItemRespVO>> getUserSessionPage(@Validated UserSessionPageReqVO reqVO) {
// 获得 Session 分页
PageResult<UserSessionDO> pageResult = userSessionService.getUserSessionPage(reqVO);
// 获得拼接需要的数据
Map<Long, AdminUserDO> userMap = userService.getUserMap(
convertList(pageResult.getList(), UserSessionDO::getUserId));
Map<Long, DeptDO> deptMap = deptService.getDeptMap(
convertList(userMap.values(), AdminUserDO::getDeptId));
// 拼接结果返回
List<UserSessionPageItemRespVO> sessionList = new ArrayList<>(pageResult.getList().size());
pageResult.getList().forEach(session -> {
UserSessionPageItemRespVO respVO = UserSessionConvert.INSTANCE.convert(session);
sessionList.add(respVO);
// 设置用户账号
MapUtils.findAndThen(userMap, session.getUserId(), user -> {
respVO.setUsername(user.getUsername());
// 设置用户部门
MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> respVO.setDeptName(dept.getName()));
});
});
return success(new PageResult<>(sessionList, pageResult.getTotal()));
}
@DeleteMapping("/delete")
@ApiOperation("删除 Session")
@ApiImplicitParam(name = "id", value = "Session 编号", required = true, dataTypeClass = String.class,
example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
@PreAuthorize("@ss.hasPermission('system:user-session:delete')")
public CommonResult<Boolean> deleteUserSession(@RequestParam("id") String id) {
userSessionService.deleteUserSession(id);
return success(true);
}
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@ApiModel("管理后台 - 登录 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginRespVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
private Long userId;
@ApiModelProperty(value = "访问令牌", required = true, example = "happy")
private String accessToken;
@ApiModelProperty(value = "刷新令牌", required = true, example = "nice")
private String refreshToken;
@ApiModelProperty(value = "过期时间", required = true)
private Date expiresTime;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@ApiModel("管理后台 - 短信验证码的呢老姑 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSmsLoginReqVO {
@ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "手机号不能为空")
@Length(min = 11, max = 11, message = "手机号格式错误,仅支持大陆手机号")
@Pattern(regexp = "^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$", message = "账号格式为数字以及字母")
private String mobile;
@ApiModelProperty(value = "短信验证码", required = true, example = "1024", notes = "验证码开启时,需要传递")
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
private String code;
/**
* 开启验证码的 Group
*/
public interface CodeEnableGroup {}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 发送手机验证码 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSmsSendReqVO {
@ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma")
@NotEmpty(message = "手机号不能为空")
@Mobile
private String mobile;
@ApiModelProperty(value = "短信场景", required = true, example = "1")
@NotNull(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;

View File

@@ -1,20 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("管理后台 - 账号密码登录 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginRespVO {
@ApiModelProperty(value = "token", required = true, example = "yudaoyuanma")
private String token;
}

View File

@@ -1,38 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.session;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.Date;
@ApiModel(value = "管理后台 - 用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class UserSessionPageItemRespVO extends PageParam {
@ApiModelProperty(value = "Session 编号", required = true, example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
private String id;
@ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
private String userIp;
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
private String userAgent;
@ApiModelProperty(value = "登录时间", required = true)
private Date createTime;
@ApiModelProperty(value = "用户账号", required = true, example = "yudao")
private String username;
@ApiModelProperty(value = "部门名称", example = "研发部")
private String deptName;
}

View File

@@ -1,20 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.session;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 在线用户 Session 分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class UserSessionPageReqVO extends PageParam {
@ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配")
private String userIp;
@ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
private String username;
}

View File

@@ -0,0 +1,23 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/system/oauth2-client/create
Content-Type: application/json
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
{
"id": "1",
"secret": "admin123",
"name": "芋道源码",
"logo": "https://www.iocoder.cn/images/favicon.ico",
"description": "我是描述",
"status": 0,
"accessTokenValiditySeconds": 180,
"refreshTokenValiditySeconds": 8640,
"redirectUris": ["https://www.iocoder.cn"],
"autoApprove": true,
"authorizedGrantTypes": ["password"],
"scopes": ["user_info"],
"authorities": ["system:user:query"],
"resource_ids": ["1024"],
"additionalInformation": "{}"
}

View File

@@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - OAuth2 客户端")
@RestController
@RequestMapping("/system/oauth2-client")
@Validated
public class OAuth2ClientController {
@Resource
private OAuth2ClientService oAuth2ClientService;
@PostMapping("/create")
@ApiOperation("创建 OAuth2 客户端")
@PreAuthorize("@ss.hasPermission('system:oauth2-client:create')")
public CommonResult<Long> createOAuth2Client(@Valid @RequestBody OAuth2ClientCreateReqVO createReqVO) {
return success(oAuth2ClientService.createOAuth2Client(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新 OAuth2 客户端")
@PreAuthorize("@ss.hasPermission('system:oauth2-client:update')")
public CommonResult<Boolean> updateOAuth2Client(@Valid @RequestBody OAuth2ClientUpdateReqVO updateReqVO) {
oAuth2ClientService.updateOAuth2Client(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除 OAuth2 客户端")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')")
public CommonResult<Boolean> deleteOAuth2Client(@RequestParam("id") Long id) {
oAuth2ClientService.deleteOAuth2Client(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得 OAuth2 客户端")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:oauth2-client:query')")
public CommonResult<OAuth2ClientRespVO> getOAuth2Client(@RequestParam("id") Long id) {
OAuth2ClientDO oAuth2Client = oAuth2ClientService.getOAuth2Client(id);
return success(OAuth2ClientConvert.INSTANCE.convert(oAuth2Client));
}
@GetMapping("/page")
@ApiOperation("获得OAuth2 客户端分页")
@PreAuthorize("@ss.hasPermission('system:oauth2-client:query')")
public CommonResult<PageResult<OAuth2ClientRespVO>> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) {
PageResult<OAuth2ClientDO> pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO);
return success(OAuth2ClientConvert.INSTANCE.convertPage(pageResult));
}
}

View File

@@ -0,0 +1,69 @@
### 请求 /system/oauth2/authorize 接口 => 成功
GET {{baseUrl}}/system/oauth2/authorize?clientId=default
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/authorize + token 接口 => 成功
POST {{baseUrl}}/system/oauth2/authorize
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
response_type=token&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true
### 请求 /system/oauth2/authorize + code 接口 => 成功
POST {{baseUrl}}/system/oauth2/authorize
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
response_type=code&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=false
### 请求 /system/oauth2/token + code 接口 => 成功
POST {{baseUrl}}/system/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
grant_type=authorization_code&redirect_uri=https://www.iocoder.cn&code=189956c07a174588a97157eabef2f93a
### 请求 /system/oauth2/token + password 接口 => 成功
POST {{baseUrl}}/system/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
grant_type=password&username=admin&password=admin123&scope=user.read
### 请求 /system/oauth2/token + refresh_token 接口 => 成功
POST {{baseUrl}}/system/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588
### 请求 /system/oauth2/token + DELETE 接口 => 成功
DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/check-token 接口 => 成功
POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/user/get 接口 => 成功
GET {{baseUrl}}/system/oauth2/user/get
Authorization: Bearer 9502bd7a768a4ade920b90f41e2efd5c
tenant-id: {{adminTenentId}}
### 请求 /system/oauth2/user/update 接口 => 成功
PUT {{baseUrl}}/system/oauth2/user/update
Content-Type: application/json
Authorization: Bearer 9502bd7a768a4ade920b90f41e2efd5c
tenant-id: {{adminTenentId}}
{
"nickname": "芋道源码"
}

View File

@@ -0,0 +1,348 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* 提供给外部应用调用为主
*
* 一般来说,管理后台的 /system-api/* 是不直接提供给外部应用使用,主要是外部应用能够访问的数据与接口是有限的,而管理后台的 RBAC 无法很好的控制。
* 参考大量的开放平台,都是独立的一套 OpenAPI对应到【本系统】就是在 Controller 下新建 open 包,实现 /open-api/* 接口,然后通过 scope 进行控制。
* 另外,一个公司如果有多个管理后台,它们 client_id 产生的 access token 相互之间是无法互通的,即无法访问它们系统的 API 接口,直到两个 client_id 产生信任授权。
*
* 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。
* scope 的使用示例,可见当前类的 getUserInfo 和 updateUserInfo 方法,上面有 @PreAuthorize("@ss.hasScope('user.read')") 和 @PreAuthorize("@ss.hasScope('user.write')") 注解
*
* @author 芋道源码
*/
@Api(tags = "管理后台 - OAuth2.0 授权")
@RestController
@RequestMapping("/system/oauth2")
@Validated
@Slf4j
public class OAuth2OpenController {
@Resource
private OAuth2GrantService oauth2GrantService;
@Resource
private OAuth2ClientService oauth2ClientService;
@Resource
private OAuth2ApproveService oauth2ApproveService;
@Resource
private OAuth2TokenService oauth2TokenService;
/**
* 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法
*
* 授权码 authorization_code 模式时code + redirectUri + state 参数
* 密码 password 模式时username + password + scope 参数
* 刷新 refresh_token 模式时refreshToken 参数
* 客户端 client_credentials 模式scope 参数
* 简化 implicit 模式时:不支持
*
* 注意,默认需要传递 client_id + client_secret 参数
*/
@PostMapping("/token")
@ApiOperation(value = "获得访问令牌", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用")
@ApiImplicitParams({
@ApiImplicitParam(name = "grant_type", required = true, value = "授权类型", example = "code", dataTypeClass = String.class),
@ApiImplicitParam(name = "code", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class),
@ApiImplicitParam(name = "redirect_uri", value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class),
@ApiImplicitParam(name = "username", example = "tudou", dataTypeClass = String.class),
@ApiImplicitParam(name = "password", example = "cai", dataTypeClass = String.class), // 多个使用空格分隔
@ApiImplicitParam(name = "scope", example = "user_info", dataTypeClass = String.class)
})
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request,
@RequestParam("grant_type") String grantType,
@RequestParam(value = "code", required = false) String code, // 授权码模式
@RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式
@RequestParam(value = "state", required = false) String state, // 授权码模式
@RequestParam(value = "username", required = false) String username, // 密码模式
@RequestParam(value = "password", required = false) String password, // 密码模式
@RequestParam(value = "scope", required = false) String scope, // 密码模式
@RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式
List<String> scopes = OAuth2Utils.buildScopes(scope);
// 授权类型
OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGranType(grantType);
if (grantTypeEnum == null) {
throw exception0(BAD_REQUEST.getCode(), StrUtil.format("未知授权类型({})", grantType));
}
if (grantTypeEnum == OAuth2GrantTypeEnum.IMPLICIT) {
throw exception0(BAD_REQUEST.getCode(), "Token 接口不支持 implicit 授权模式");
}
// 校验客户端
String[] clientIdAndSecret = obtainBasicAuthorization(request);
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
grantType, scopes, redirectUri);
// 根据授权模式,获取访问令牌
OAuth2AccessTokenDO accessTokenDO;
switch (grantTypeEnum) {
case AUTHORIZATION_CODE:
accessTokenDO = oauth2GrantService.grantAuthorizationCodeForAccessToken(client.getClientId(), code, redirectUri, state);
break;
case PASSWORD:
accessTokenDO = oauth2GrantService.grantPassword(username, password, client.getClientId(), scopes);
break;
case CLIENT_CREDENTIALS:
accessTokenDO = oauth2GrantService.grantClientCredentials(client.getClientId(), scopes);
break;
case REFRESH_TOKEN:
accessTokenDO = oauth2GrantService.grantRefreshToken(refreshToken, client.getClientId());
break;
default:
throw new IllegalArgumentException("未知授权类型:" + grantType);
}
Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
return success(OAuth2OpenConvert.INSTANCE.convert(accessTokenDO));
}
@DeleteMapping("/token")
@ApiOperation(value = "删除访问令牌")
@ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class)
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> revokeToken(HttpServletRequest request,
@RequestParam("token") String token) {
// 校验客户端
String[] clientIdAndSecret = obtainBasicAuthorization(request);
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
null, null, null);
// 删除访问令牌
return success(oauth2GrantService.revokeToken(client.getClientId(), token));
}
/**
* 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法
*/
@PostMapping("/check-token")
@ApiOperation(value = "校验访问令牌")
@ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class)
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<OAuth2OpenCheckTokenRespVO> checkToken(HttpServletRequest request,
@RequestParam("token") String token) {
// 校验客户端
String[] clientIdAndSecret = obtainBasicAuthorization(request);
oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1],
null, null, null);
// 校验令牌
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(token);
Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
return success(OAuth2OpenConvert.INSTANCE.convert2(accessTokenDO));
}
/**
* 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 authorize 方法
*/
@GetMapping("/authorize")
@ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用")
@ApiImplicitParam(name = "clientId", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class)
public CommonResult<OAuth2OpenAuthorizeInfoRespVO> authorize(@RequestParam("clientId") String clientId) {
// 0. 校验用户已经登录。通过 Spring Security 实现
// 1. 获得 Client 客户端的信息
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null,
null, null, null);
// 2. 获得用户已经授权的信息
List<OAuth2ApproveDO> approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId);
// 拼接返回
return success(OAuth2OpenConvert.INSTANCE.convert(client, approves));
}
/**
* 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 approveOrDeny 方法
*
* 场景一:【自动授权 autoApprove = true】
* 刚进入 sso.vue 界面,调用该接口,用户历史已经给该应用做过对应的授权,或者 OAuth2Client 支持该 scope 的自动授权
* 场景二:【手动授权 autoApprove = false】
* 在 sso.vue 界面,用户选择好 scope 授权范围调用该接口进行授权。此时approved 为 true 或者 false
*
* 因为前后端分离Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL剩余交给前端处理
*/
@PostMapping("/authorize")
@ApiOperation(value = "申请授权", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【提交】调用")
@ApiImplicitParams({
@ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class),
@ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class),
@ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 使用 Map<String, Boolean> 格式Spring MVC 暂时不支持这么接收参数
@ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class),
@ApiImplicitParam(name = "autoApprove", required = true, value = "用户是否接受", example = "true", dataTypeClass = Boolean.class),
@ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class)
})
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<String> approveOrDeny(@RequestParam("response_type") String responseType,
@RequestParam("client_id") String clientId,
@RequestParam(value = "scope", required = false) String scope,
@RequestParam("redirect_uri") String redirectUri,
@RequestParam(value = "auto_approve") Boolean autoApprove,
@RequestParam(value = "state", required = false) String state) {
@SuppressWarnings("unchecked")
Map<String, Boolean> scopes = JsonUtils.parseObject(scope, Map.class);
scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap());
// TODO 芋艿:针对 approved + scopes 在看看 spring security 的实现
// 0. 校验用户已经登录。通过 Spring Security 实现
// 1.1 校验 responseType 是否满足 code 或者 token 值
OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType);
// 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null,
grantTypeEnum.getGrantType(), scopes.keySet(), redirectUri);
// 2.1 假设 approved 为 null说明是场景一
if (Boolean.TRUE.equals(autoApprove)) {
// 如果无法自动授权通过,则返回空 url前端不进行跳转
if (!oauth2ApproveService.checkForPreApproval(getLoginUserId(), getUserType(), clientId, scopes.keySet())) {
return success(null);
}
} else { // 2.2 假设 approved 非 null说明是场景二
// 如果计算后不通过,则跳转一个错误链接
if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), getUserType(), clientId, scopes)) {
return success(OAuth2Utils.buildUnsuccessfulRedirect(redirectUri, responseType, state,
"access_denied", "User denied access"));
}
}
// 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向
List<String> approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue);
if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) {
return success(getAuthorizationCodeRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
}
// 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向
return success(getImplicitGrantRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
}
private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) {
if (StrUtil.equals(responseType, "code")) {
return OAuth2GrantTypeEnum.AUTHORIZATION_CODE;
}
if (StrUtil.equalsAny(responseType, "token")) {
return OAuth2GrantTypeEnum.IMPLICIT;
}
throw exception0(BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token");
}
private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client,
List<String> scopes, String redirectUri, String state) {
// 1. 创建 access token 访问令牌
OAuth2AccessTokenDO accessTokenDO = oauth2GrantService.grantImplicit(userId, getUserType(), client.getClientId(), scopes);
Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
// 2. 拼接重定向的 URL
// noinspection unchecked
return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(),
scopes, JsonUtils.parseObject(client.getAdditionalInformation(), Map.class));
}
private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client,
List<String> scopes, String redirectUri, String state) {
// 1. 创建 code 授权码
String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId,getUserType(), client.getClientId(), scopes,
redirectUri, state);
// 2. 拼接重定向的 URL
return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state);
}
private Integer getUserType() {
return UserTypeEnum.ADMIN.getValue();
}
private String[] obtainBasicAuthorization(HttpServletRequest request) {
String[] clientIdAndSecret = HttpUtils.obtainBasicAuthorization(request);
if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) {
throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递");
}
return clientIdAndSecret;
}
// ============ 用户操作的示例,展示 scope 的使用 ============
@Resource
private AdminUserService userService;
@Resource
private DeptService deptService;
@Resource
private PostService postService;
@GetMapping("/user/get")
@ApiOperation("获得用户基本信息")
@PreAuthorize("@ss.hasScope('user.read')")
public CommonResult<OAuth2OpenUserInfoRespVO> getUserInfo() {
// 获得用户基本信息
AdminUserDO user = userService.getUser(getLoginUserId());
OAuth2OpenUserInfoRespVO resp = OAuth2OpenConvert.INSTANCE.convert(user);
// 获得部门信息
if (user.getDeptId() != null) {
DeptDO dept = deptService.getDept(user.getDeptId());
resp.setDept(OAuth2OpenConvert.INSTANCE.convert(dept));
}
// 获得岗位信息
if (CollUtil.isNotEmpty(user.getPostIds())) {
List<PostDO> posts = postService.getPosts(user.getPostIds());
resp.setPosts(OAuth2OpenConvert.INSTANCE.convertList(posts));
}
return success(resp);
}
@PutMapping("/user/update")
@ApiOperation("更新用户基本信息")
@PreAuthorize("@ss.hasScope('user.write')")
public CommonResult<Boolean> updateUserInfo(@Valid @RequestBody OAuth2OpenUserUpdateReqVO reqVO) {
// 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。
// 主要是AdminUserService 没有自己的 BO 对象,所以复用只能这么做
userService.updateUserProfile(getLoginUserId(), OAuth2OpenConvert.INSTANCE.convert(reqVO));
return success(true);
}
}

View File

@@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO;
import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - OAuth2.0 令牌")
@RestController
@RequestMapping("/system/oauth2-token")
public class OAuth2TokenController {
@Resource
private OAuth2TokenService oauth2TokenService;
@Resource
private AdminAuthService authService;
@GetMapping("/page")
@ApiOperation(value = "获得访问令牌分页", notes = "只返回有效期内的")
@PreAuthorize("@ss.hasPermission('system:oauth2-token:page')")
public CommonResult<PageResult<OAuth2AccessTokenRespVO>> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) {
PageResult<OAuth2AccessTokenDO> pageResult = oauth2TokenService.getAccessTokenPage(reqVO);
return success(OAuth2TokenConvert.INSTANCE.convert(pageResult));
}
@DeleteMapping("/delete")
@ApiOperation("删除访问令牌")
@ApiImplicitParam(name = "accessToken", value = "访问令牌", required = true, dataTypeClass = String.class, example = "tudou")
@PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')")
public CommonResult<Boolean> deleteAccessToken(@RequestParam("accessToken") String accessToken) {
authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType());
return success(true);
}
}

View File

@@ -0,0 +1,82 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* OAuth2 客户端 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class OAuth2ClientBaseVO {
@ApiModelProperty(value = "客户端编号", required = true, example = "tudou")
@NotNull(message = "客户端编号不能为空")
private String clientId;
@ApiModelProperty(value = "客户端密钥", required = true, example = "fan")
@NotNull(message = "客户端密钥不能为空")
private String secret;
@ApiModelProperty(value = "应用名", required = true, example = "土豆")
@NotNull(message = "应用名不能为空")
private String name;
@ApiModelProperty(value = "应用图标", required = true, example = "https://www.iocoder.cn/xx.png")
@NotNull(message = "应用图标不能为空")
@URL(message = "应用图标的地址不正确")
private String logo;
@ApiModelProperty(value = "应用描述", example = "我是一个应用")
private String description;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
private Integer status;
@ApiModelProperty(value = "访问令牌的有效期", required = true, example = "8640")
@NotNull(message = "访问令牌的有效期不能为空")
private Integer accessTokenValiditySeconds;
@ApiModelProperty(value = "刷新令牌的有效期", required = true, example = "8640000")
@NotNull(message = "刷新令牌的有效期不能为空")
private Integer refreshTokenValiditySeconds;
@ApiModelProperty(value = "可重定向的 URI 地址", required = true, example = "https://www.iocoder.cn")
@NotNull(message = "可重定向的 URI 地址不能为空")
private List<@NotEmpty(message = "重定向的 URI 不能为空")
@URL(message = "重定向的 URI 格式不正确") String> redirectUris;
@ApiModelProperty(value = "授权类型", required = true, example = "password", notes = "参见 OAuth2GrantTypeEnum 枚举")
@NotNull(message = "授权类型不能为空")
private List<String> authorizedGrantTypes;
@ApiModelProperty(value = "授权范围", example = "user_info")
private List<String> scopes;
@ApiModelProperty(value = "自动通过的授权范围", example = "user_info")
private List<String> autoApproveScopes;
@ApiModelProperty(value = "权限", example = "system:user:query")
private List<String> authorities;
@ApiModelProperty(value = "资源", example = "1024")
private List<String> resourceIds;
@ApiModelProperty(value = "附加信息", example = "{yunai: true}")
private String additionalInformation;
@AssertTrue(message = "附加信息必须是 JSON 格式")
public boolean isAdditionalInformationJson() {
return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation);
}
}

View File

@@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import lombok.*;
import io.swagger.annotations.*;
@ApiModel("管理后台 - OAuth2 客户端创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientCreateReqVO extends OAuth2ClientBaseVO {
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import lombok.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ApiModel("管理后台 - OAuth2 客户端分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientPageReqVO extends PageParam {
@ApiModelProperty(value = "应用名", example = "土豆", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "状态", example = "1", notes = "参见 CommonStatusEnum 枚举")
private Integer status;
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - OAuth2 客户端 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientRespVO extends OAuth2ClientBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - OAuth2 客户端更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OAuth2ClientUpdateReqVO extends OAuth2ClientBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
@NotNull(message = "编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("管理后台 - 【开放接口】访问令牌 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2OpenAccessTokenRespVO {
@ApiModelProperty(value = "访问令牌", required = true, example = "tudou")
@JsonProperty("access_token")
private String accessToken;
@ApiModelProperty(value = "刷新令牌", required = true, example = "nice")
@JsonProperty("refresh_token")
private String refreshToken;
@ApiModelProperty(value = "令牌类型", required = true, example = "bearer")
@JsonProperty("token_type")
private String tokenType;
@ApiModelProperty(value = "过期时间", required = true, example = "42430", notes = "单位:秒")
@JsonProperty("expires_in")
private Long expiresIn;
@ApiModelProperty(value = "授权范围", example = "user_info", notes = "如果多个授权范围,使用空格分隔")
private String scope;
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@ApiModel("管理后台 - 授权页的信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2OpenAuthorizeInfoRespVO {
/**
* 客户端
*/
private Client client;
@ApiModelProperty(value = "scope 的选中信息", required = true, notes = "使用 List 保证有序性Key 是 scopeValue 为是否选中")
private List<KeyValue<String, Boolean>> scopes;
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Client {
@ApiModelProperty(value = "应用名", required = true, example = "土豆")
private String name;
@ApiModelProperty(value = "应用图标", required = true, example = "https://www.iocoder.cn/xx.png")
private String logo;
}
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
@ApiModel("管理后台 - 【开放接口】校验令牌 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2OpenCheckTokenRespVO {
@ApiModelProperty(value = "用户编号", required = true, example = "666")
@JsonProperty("user_id")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举")
@JsonProperty("user_type")
private Integer userType;
@ApiModelProperty(value = "租户编号", required = true, example = "1024")
@JsonProperty("tenant_id")
private Long tenantId;
@ApiModelProperty(value = "客户端编号", required = true, example = "car")
private String clientId;
@ApiModelProperty(value = "授权范围", required = true, example = "user_info")
private Set<String> scopes;
@ApiModelProperty(value = "访问令牌", required = true, example = "tudou")
@JsonProperty("access_token")
private String accessToken;
@ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000即单位")
@JsonProperty("exp")
private Long exp;
}

View File

@@ -0,0 +1,71 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@ApiModel("管理后台 - 【开放接口】获得用户基本信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2OpenUserInfoRespVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
private String username;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋道")
private String nickname;
@ApiModelProperty(value = "用户邮箱", example = "yudao@iocoder.cn")
private String email;
@ApiModelProperty(value = "手机号码", example = "15601691300")
private String mobile;
@ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SexEnum 枚举类")
private Integer sex;
@ApiModelProperty(value = "用户头像", example = "https://www.iocoder.cn/xxx.png")
private String avatar;
/**
* 所在部门
*/
private Dept dept;
/**
* 所属岗位数组
*/
private List<Post> posts;
@ApiModel("部门")
@Data
public static class Dept {
@ApiModelProperty(value = "部门编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "部门名称", required = true, example = "研发部")
private String name;
}
@ApiModel("岗位")
@Data
public static class Post {
@ApiModelProperty(value = "岗位编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "岗位名称", required = true, example = "开发")
private String name;
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
@ApiModel("管理后台 - 【开放接口】更新用户基本信息 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2OpenUserUpdateReqVO {
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
@Size(max = 30, message = "用户昵称长度不能超过 30 个字符")
private String nickname;
@ApiModelProperty(value = "用户邮箱", example = "yudao@iocoder.cn")
@Email(message = "邮箱格式不正确")
@Size(max = 50, message = "邮箱长度不能超过 50 个字符")
private String email;
@ApiModelProperty(value = "手机号码", example = "15601691300")
@Length(min = 11, max = 11, message = "手机号长度必须 11 位")
private String mobile;
@ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SexEnum 枚举类")
private Integer sex;
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel("管理后台 - 访问令牌分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class OAuth2AccessTokenPageReqVO extends PageParam {
@ApiModelProperty(value = "用户编号", required = true, example = "666")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举")
private Integer userType;
@ApiModelProperty(value = "客户端编号", required = true, example = "2")
private String clientId;
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@ApiModel("管理后台 - 访问令牌 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2AccessTokenRespVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "访问令牌", required = true, example = "tudou")
private String accessToken;
@ApiModelProperty(value = "刷新令牌", required = true, example = "nice")
private String refreshToken;
@ApiModelProperty(value = "用户编号", required = true, example = "666")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举")
private Integer userType;
@ApiModelProperty(value = "客户端编号", required = true, example = "2")
private String clientId;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
@ApiModelProperty(value = "过期时间", required = true)
private Date expiresTime;
}

View File

@@ -46,7 +46,6 @@ public class UserProfileController {
private AdminUserService userService;
@Resource
private DeptService deptService;
@Resource
private PostService postService;
@Resource

View File

@@ -13,7 +13,7 @@ import javax.validation.constraints.Size;
public class UserProfileUpdateReqVO {
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
@Size(max = 30, message = "用户昵称长度不能超过30个字符")
@Size(max = 30, message = "用户昵称长度不能超过 30 个字符")
private String nickname;
@ApiModelProperty(value = "用户邮箱", example = "yudao@iocoder.cn")

View File

@@ -1,17 +1,16 @@
package cn.iocoder.yudao.module.system.convert.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import org.slf4j.LoggerFactory;
@@ -22,13 +21,7 @@ public interface AuthConvert {
AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class);
@Mapping(source = "updateTime", target = "updateTime", ignore = true) // 字段相同,但是含义不同,忽略
LoginUser convert0(AdminUserDO bean);
default LoginUser convert(AdminUserDO bean) {
// 目的,为了设置 UserTypeEnum.ADMIN.getValue()
return convert0(bean).setUserType(UserTypeEnum.ADMIN.getValue());
}
AuthLoginRespVO convert(OAuth2AccessTokenDO bean);
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
return AuthPermissionInfoRespVO.builder()
@@ -73,7 +66,10 @@ public interface AuthConvert {
}
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialBindLoginReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialQuickLoginReqVO reqVO);
SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO);
SmsCodeUseReqDTO convert(AuthSmsLoginReqVO reqVO, Integer scene, String usedIp);
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.convert.auth;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* OAuth2 客户端 Convert
*
* @author 芋道源码
*/
@Mapper
public interface OAuth2ClientConvert {
OAuth2ClientConvert INSTANCE = Mappers.getMapper(OAuth2ClientConvert.class);
OAuth2ClientDO convert(OAuth2ClientCreateReqVO bean);
OAuth2ClientDO convert(OAuth2ClientUpdateReqVO bean);
OAuth2ClientRespVO convert(OAuth2ClientDO bean);
List<OAuth2ClientRespVO> convertList(List<OAuth2ClientDO> list);
PageResult<OAuth2ClientRespVO> convertPage(PageResult<OAuth2ClientDO> page);
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.system.convert.auth;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface OAuth2TokenConvert {
OAuth2TokenConvert INSTANCE = Mappers.getMapper(OAuth2TokenConvert.class);
OAuth2AccessTokenCheckRespDTO convert(OAuth2AccessTokenDO bean);
PageResult<OAuth2AccessTokenRespVO> convert(PageResult<OAuth2AccessTokenDO> page);
OAuth2AccessTokenRespDTO convert2(OAuth2AccessTokenDO bean);
}

View File

@@ -1,15 +0,0 @@
package cn.iocoder.yudao.module.system.convert.auth;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserSessionConvert {
UserSessionConvert INSTANCE = Mappers.getMapper(UserSessionConvert.class);
UserSessionPageItemRespVO convert(UserSessionDO session);
}

View File

@@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.system.convert.oauth2;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Mapper
public interface OAuth2OpenConvert {
OAuth2OpenConvert INSTANCE = Mappers.getMapper(OAuth2OpenConvert.class);
default OAuth2OpenAccessTokenRespVO convert(OAuth2AccessTokenDO bean) {
OAuth2OpenAccessTokenRespVO respVO = convert0(bean);
respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase());
respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime()));
respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes()));
return respVO;
}
OAuth2OpenAccessTokenRespVO convert0(OAuth2AccessTokenDO bean);
default OAuth2OpenCheckTokenRespVO convert2(OAuth2AccessTokenDO bean) {
OAuth2OpenCheckTokenRespVO respVO = convert3(bean);
respVO.setExp(bean.getExpiresTime().getTime() / 1000L);
respVO.setUserType(UserTypeEnum.ADMIN.getValue());
return respVO;
}
OAuth2OpenCheckTokenRespVO convert3(OAuth2AccessTokenDO bean);
// ============ 用户操作的示例 ============
OAuth2OpenUserInfoRespVO convert(AdminUserDO bean);
OAuth2OpenUserInfoRespVO.Dept convert(DeptDO dept);
List<OAuth2OpenUserInfoRespVO.Post> convertList(List<PostDO> list);
UserProfileUpdateReqVO convert(OAuth2OpenUserUpdateReqVO bean);
default OAuth2OpenAuthorizeInfoRespVO convert(OAuth2ClientDO client, List<OAuth2ApproveDO> approves) {
// 构建 scopes
List<KeyValue<String, Boolean>> scopes = new ArrayList<>(client.getScopes().size());
Map<String, OAuth2ApproveDO> approveMap = CollectionUtils.convertMap(approves, OAuth2ApproveDO::getScope);
client.getScopes().forEach(scope -> {
OAuth2ApproveDO approve = approveMap.get(scope);
scopes.add(new KeyValue<>(scope, approve != null ? approve.getApproved() : false));
});
// 拼接返回
return new OAuth2OpenAuthorizeInfoRespVO(
new OAuth2OpenAuthorizeInfoRespVO.Client(client.getName(), client.getLogo()), scopes);
}
}

View File

@@ -1,68 +0,0 @@
package cn.iocoder.yudao.module.system.dal.dataobject.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* 在线用户表
*
* 我们已经将 {@link LoginUser} 缓存在 Redis 当中。
* 这里额外存储在线用户到 MySQL 中,目的是为了方便管理界面可以灵活查询。
* 同时,通过定时轮询 UserSessionDO 表,可以主动删除 Redis 的缓存,因为 Redis 的过期删除是延迟的。
*
* @author 芋道源码
*/
@TableName(value = "system_user_session", autoResultMap = true)
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
public class UserSessionDO extends BaseDO {
/**
* 会话编号, 即 sessionId
*/
@TableId(type = IdType.INPUT)
private String id;
/**
* 用户编号
*
* 关联 AdminUserDO.id 或者 MemberUserDO.id
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 用户账号
*
* 冗余,因为账号可以变更
*/
private String username;
/**
* 用户 IP
*/
private String userIp;
/**
* 浏览器 UA
*/
private String userAgent;
/**
* 会话超时时间
*/
private Date sessionTimeout;
}

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -15,6 +16,7 @@ import lombok.EqualsAndHashCode;
* @author 芋道源码
*/
@TableName("system_dept")
@KeySequence("system_dept_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class DeptDO extends BaseDO {

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -13,6 +14,7 @@ import lombok.EqualsAndHashCode;
* @author ruoyi
*/
@TableName("system_post")
@KeySequence("system_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class PostDO extends BaseDO {

View File

@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 用户和岗位关联
*
* @author ruoyi
*/
@TableName("system_user_post")
@KeySequence("system_user_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class UserPostDO extends BaseDO {
/**
* 自增主键
*/
@TableId
private Long id;
/**
* 用户 ID
*
* 关联 {@link AdminUserDO#getId()}
*/
private Long userId;
/**
* 角色 ID
*
* 关联 {@link PostDO#getId()}
*/
private Long postId;
}

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.dict;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -13,6 +14,7 @@ import lombok.EqualsAndHashCode;
* @author ruoyi
*/
@TableName("system_dict_data")
@KeySequence("system_dict_data_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class DictDataDO extends BaseDO {

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.dict;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -13,6 +14,7 @@ import lombok.*;
* @author ruoyi
*/
@TableName("system_dict_type")
@KeySequence("system_dict_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@@ -33,7 +35,6 @@ public class DictTypeDO extends BaseDO {
/**
* 字典类型
*/
@TableField("`type`")
private String type;
/**
* 状态

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.errorcode;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.errorcode.ErrorCodeTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -14,6 +15,7 @@ import lombok.ToString;
* @author 芋道源码
*/
@TableName(value = "system_error_code")
@KeySequence("system_error_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -17,6 +18,7 @@ import lombok.ToString;
* @author 芋道源码
*/
@TableName("system_login_log")
@KeySequence("system_login_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -20,6 +21,7 @@ import java.util.Map;
* @author 芋道源码
*/
@TableName(value = "system_operate_log", autoResultMap = true)
@KeySequence("system_operate_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class OperateLogDO extends BaseDO {
@@ -70,7 +72,6 @@ public class OperateLogDO extends BaseDO {
*
* 枚举 {@link OperateTypeEnum}
*/
@TableField("operate_type")
private Integer type;
/**
* 操作内容,记录整个操作的明细

View File

@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.notice;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.notice.NoticeTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -14,6 +14,7 @@ import lombok.EqualsAndHashCode;
* @author ruoyi
*/
@TableName("system_notice")
@KeySequence("system_notice_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class NoticeDO extends BaseDO {
@@ -31,7 +32,6 @@ public class NoticeDO extends BaseDO {
*
* 枚举 {@link NoticeTypeEnum}
*/
@TableField("notice_type")
private Integer type;
/**
* 公告内容

View File

@@ -0,0 +1,71 @@
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List;
/**
* OAuth2 访问令牌 DO
*
* 如下字段,暂时未使用,暂时不支持:
* user_name、authentication用户信息
*
* @author 芋道源码
*/
@TableName("system_oauth2_access_token")
@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class OAuth2AccessTokenDO extends TenantBaseDO {
/**
* 编号,数据库递增
*/
@TableId
private Long id;
/**
* 访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 客户端编号
*
* 关联 {@link OAuth2ClientDO#getId()}
*/
private String clientId;
/**
* 授权范围
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> scopes;
/**
* 过期时间
*/
private Date expiresTime;
}

View File

@@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* OAuth2 批准 DO
*
* 用户在 sso.vue 界面时,记录接受的 scope 列表
*
* @author 芋道源码
*/
@TableName(value = "system_oauth2_approve", autoResultMap = true)
@KeySequence("system_oauth2_approve_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class OAuth2ApproveDO extends BaseDO {
/**
* 编号,数据库自增
*/
@TableId
private Long id;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 客户端编号
*
* 关联 {@link OAuth2ClientDO#getId()}
*/
private String clientId;
/**
* 授权范围
*/
private String scope;
/**
* 是否接受
*
* true - 接受
* false - 拒绝
*/
private Boolean approved;
/**
* 过期时间
*/
private Date expiresTime;
}

View File

@@ -0,0 +1,107 @@
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* OAuth2 客户端 DO
*
* @author 芋道源码
*/
@TableName(value = "system_oauth2_client", autoResultMap = true)
@KeySequence("system_oauth2_client_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class OAuth2ClientDO extends BaseDO {
/**
* 编号,数据库自增
*
* 由于 SQL Server 在存储 String 主键有点问题,所以暂时使用 Long 类型
*/
@TableId
private Long id;
/**
* 客户端编号
*/
private String clientId;
/**
* 客户端密钥
*/
private String secret;
/**
* 应用名
*/
private String name;
/**
* 应用图标
*/
private String logo;
/**
* 应用描述
*/
private String description;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 访问令牌的有效期
*/
private Integer accessTokenValiditySeconds;
/**
* 刷新令牌的有效期
*/
private Integer refreshTokenValiditySeconds;
/**
* 可重定向的 URI 地址
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> redirectUris;
/**
* 授权类型(模式)
*
* 枚举 {@link OAuth2GrantTypeEnum}
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> authorizedGrantTypes;
/**
* 授权范围
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> scopes;
/**
* 自动授权的 Scope
*
* code 授权时,如果 scope 在这个范围内,则自动通过
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> autoApproveScopes;
/**
* 权限
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> authorities;
/**
* 资源
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> resourceIds;
/**
* 附加信息JSON 格式
*/
private String additionalInformation;
}

View File

@@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.util.List;
/**
* OAuth2 授权码 DO
*
* @author 芋道源码
*/
@TableName(value = "system_oauth2_code", autoResultMap = true)
@KeySequence("system_oauth2_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class OAuth2CodeDO extends BaseDO {
/**
* 编号,数据库递增
*/
private Long id;
/**
* 授权码
*/
private String code;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 客户端编号
*
* 关联 {@link OAuth2ClientDO#getClientId()}
*/
private String clientId;
/**
* 授权范围
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> scopes;
/**
* 重定向地址
*/
private String redirectUri;
/**
* 状态
*/
private String state;
/**
* 过期时间
*/
private Date expiresTime;
}

View File

@@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List;
/**
* OAuth2 刷新令牌
*
* @author 芋道源码
*/
@TableName("system_oauth2_refresh_token")
// 由于 Oracle 的 SEQ 的名字长度有限制,所以就先用 system_oauth2_access_token_seq 吧,反正也没啥问题
@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class OAuth2RefreshTokenDO extends BaseDO {
/**
* 编号,数据库字典
*/
private Long id;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 客户端编号
*
* 关联 {@link OAuth2ClientDO#getId()}
*/
private String clientId;
/**
* 授权范围
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> scopes;
/**
* 过期时间
*/
private Date expiresTime;
}

View File

@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.permission;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -15,6 +15,7 @@ import lombok.EqualsAndHashCode;
* @author ruoyi
*/
@TableName("system_menu")
@KeySequence("system_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class MenuDO extends BaseDO {
@@ -44,7 +45,6 @@ public class MenuDO extends BaseDO {
*
* 枚举 {@link MenuTypeEnum}
*/
@TableField("menu_type")
private Integer type;
/**
* 显示顺序

View File

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -19,6 +20,7 @@ import java.util.Set;
* @author ruoyi
*/
@TableName(value = "system_role", autoResultMap = true)
@KeySequence("system_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class RoleDO extends TenantBaseDO {

View File

@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.dal.dataobject.permission;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -13,6 +13,7 @@ import lombok.EqualsAndHashCode;
* @author ruoyi
*/
@TableName("system_role_menu")
@KeySequence("system_role_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class RoleMenuDO extends TenantBaseDO {

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.dal.dataobject.permission;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -12,6 +13,7 @@ import lombok.EqualsAndHashCode;
* @author ruoyi
*/
@TableName("system_user_role")
@KeySequence("system_user_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class UserRoleDO extends BaseDO {

View File

@@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.StringLiSTTypeHandler;
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -16,6 +17,7 @@ import java.util.List;
* @author 永不言败
*/
@TableName(value = "system_sensitive_word", autoResultMap = true)
@KeySequence("system_sensitive_word_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@@ -44,7 +46,7 @@ public class SensitiveWordDO extends BaseDO {
* 例如说tag 有短信、论坛两种,敏感词 "推广" 在短信下是敏感词,在论坛下不是敏感词。
* 此时,我们会存储一条敏感词记录,它的 name 为"推广"tag 为短信。
*/
@TableField(typeHandler = StringLiSTTypeHandler.class)
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> tags;
/**
* 状态

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.sms;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -15,6 +16,7 @@ import lombok.ToString;
* @since 2021-01-25
*/
@TableName(value = "system_sms_channel", autoResultMap = true)
@KeySequence("system_sms_channel_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.dal.dataobject.sms;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -14,6 +15,7 @@ import java.util.Date;
* @author 芋道源码
*/
@TableName("system_sms_code")
@KeySequence("system_sms_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Builder

View File

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
@@ -20,6 +21,7 @@ import java.util.Map;
* @since 2021-01-25
*/
@TableName(value = "system_sms_log", autoResultMap = true)
@KeySequence("system_sms_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.sms;
import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
@@ -19,6 +20,7 @@ import java.util.List;
* @since 2021-01-25
*/
@TableName(value = "system_sms_template", autoResultMap = true)
@KeySequence("system_sms_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.social;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -12,6 +13,7 @@ import lombok.*;
* @author 芋道源码
*/
@TableName(value = "system_social_user_bind", autoResultMap = true)
@KeySequence("system_social_user_bind_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Builder

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.social;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -12,6 +13,7 @@ import lombok.*;
* @author weir
*/
@TableName(value = "system_social_user", autoResultMap = true)
@KeySequence("system_social_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Builder

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.tenant;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -14,6 +15,7 @@ import java.util.Date;
* @author 芋道源码
*/
@TableName(value = "system_tenant", autoResultMap = true)
@KeySequence("system_tenant_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.tenant;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -15,6 +16,7 @@ import java.util.Set;
* @author 芋道源码
*/
@TableName(value = "system_tenant_package", autoResultMap = true)
@KeySequence("system_tenant_package_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.system.enums.common.SexEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -18,7 +19,8 @@ import java.util.Set;
*
* @author 芋道源码
*/
@TableName(value = "system_user", autoResultMap = true)
@TableName(value = "system_users", autoResultMap = true) // 由于 SQL Server 的 system_user 是关键字,所以使用 system_users
@KeySequence("system_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@Builder

View File

@@ -1,27 +0,0 @@
package cn.iocoder.yudao.module.system.dal.mysql.auth;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@Mapper
public interface UserSessionMapper extends BaseMapperX<UserSessionDO> {
default PageResult<UserSessionDO> selectPage(UserSessionPageReqVO reqVO, Collection<Long> userIds) {
return selectPage(reqVO, new QueryWrapperX<UserSessionDO>()
.inIfPresent("user_id", userIds)
.likeIfPresent("user_ip", reqVO.getUserIp()));
}
default List<UserSessionDO> selectListBySessionTimoutLt() {
return selectList(new QueryWrapperX<UserSessionDO>().lt("session_timeout",new Date()));
}
}

View File

@@ -30,7 +30,7 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
return selectCount(DeptDO::getParentId, parentId);
}
@Select("SELECT id FROM system_dept WHERE update_time > #{maxUpdateTime} LIMIT 1")
Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
@Select("SELECT COUNT(*) FROM system_dept WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(Date maxUpdateTime);
}

View File

@@ -24,7 +24,8 @@ public interface PostMapper extends BaseMapperX<PostDO> {
return selectPage(reqVO, new QueryWrapperX<PostDO>()
.likeIfPresent("code", reqVO.getCode())
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus()));
.eqIfPresent("status", reqVO.getStatus())
.orderByDesc("id"));
}
default List<PostDO> selectList(PostExportReqVO reqVO) {

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.dal.mysql.dept;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface UserPostMapper extends BaseMapperX<UserPostDO> {
default List<UserPostDO> selectListByUserId(Long userId) {
return selectList(new LambdaQueryWrapperX<UserPostDO>()
.eq(UserPostDO::getUserId, userId));
}
default void deleteByUserIdAndPostId(Long userId, Collection<Long> postIds) {
delete(new LambdaQueryWrapperX<UserPostDO>()
.eq(UserPostDO::getUserId, userId)
.in(UserPostDO::getPostId, postIds));
}
default List<UserPostDO> selectListByPostIds(Collection<Long> postIds) {
return selectList(new LambdaQueryWrapperX<UserPostDO>()
.in(UserPostDO::getPostId, postIds));
}
default void deleteByUserId(Long userId){
delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId));
}
}

View File

@@ -37,7 +37,7 @@ public interface DictDataMapper extends BaseMapperX<DictDataDO> {
.likeIfPresent(DictDataDO::getLabel, reqVO.getLabel())
.likeIfPresent(DictDataDO::getDictType, reqVO.getDictType())
.eqIfPresent(DictDataDO::getStatus, reqVO.getStatus())
.orderByAsc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort)));
.orderByDesc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort)));
}
default List<DictDataDO> selectList(DictDataExportReqVO reqVO) {
@@ -46,7 +46,7 @@ public interface DictDataMapper extends BaseMapperX<DictDataDO> {
.eqIfPresent(DictDataDO::getStatus, reqVO.getStatus()));
}
@Select("SELECT id FROM system_dict_data WHERE update_time > #{maxUpdateTime} LIMIT 1")
Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
@Select("SELECT COUNT(*) FROM system_dict_data WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(Date maxUpdateTime);
}

View File

@@ -2,9 +2,10 @@ package cn.iocoder.yudao.module.system.dal.mysql.dict;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
import org.apache.ibatis.annotations.Mapper;
@@ -14,27 +15,28 @@ import java.util.List;
public interface DictTypeMapper extends BaseMapperX<DictTypeDO> {
default PageResult<DictTypeDO> selectPage(DictTypePageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<DictTypeDO>()
.likeIfPresent("name", reqVO.getName())
.likeIfPresent("`type`", reqVO.getType())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
return selectPage(reqVO, new LambdaQueryWrapperX<DictTypeDO>()
.likeIfPresent(DictTypeDO::getName, reqVO.getName())
.likeIfPresent(DictTypeDO::getType, reqVO.getType())
.eqIfPresent(DictTypeDO::getStatus, reqVO.getStatus())
.betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc(DictTypeDO::getId));
}
default List<DictTypeDO> selectList(DictTypeExportReqVO reqVO) {
return selectList(new QueryWrapperX<DictTypeDO>()
.likeIfPresent("name", reqVO.getName())
.likeIfPresent("`type`", reqVO.getType())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
return selectList(new LambdaQueryWrapperX<DictTypeDO>()
.likeIfPresent(DictTypeDO::getName, reqVO.getName())
.likeIfPresent(DictTypeDO::getType, reqVO.getType())
.eqIfPresent(DictTypeDO::getStatus, reqVO.getStatus())
.betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
}
default DictTypeDO selectByType(String type) {
return selectOne(new QueryWrapperX<DictTypeDO>().eq("`type`", type));
return selectOne(DictTypeDO::getType, type);
}
default DictTypeDO selectByName(String name) {
return selectOne(new QueryWrapperX<DictTypeDO>().eq("name", name));
return selectOne(DictTypeDO::getName, name);
}
}

View File

@@ -23,7 +23,7 @@ public interface ErrorCodeMapper extends BaseMapperX<ErrorCodeDO> {
.eqIfPresent("code", reqVO.getCode())
.likeIfPresent("message", reqVO.getMessage())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByAsc("application_name", "code"));
.orderByDesc("code"));
}
default List<ErrorCodeDO> selectList(ErrorCodeExportReqVO reqVO) {

View File

@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.logger;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
@@ -16,32 +16,32 @@ import java.util.List;
public interface OperateLogMapper extends BaseMapperX<OperateLogDO> {
default PageResult<OperateLogDO> selectPage(OperateLogPageReqVO reqVO, Collection<Long> userIds) {
QueryWrapperX<OperateLogDO> query = new QueryWrapperX<OperateLogDO>()
.likeIfPresent("module", reqVO.getModule())
.inIfPresent("user_id", userIds)
.eqIfPresent("operate_type", reqVO.getType())
.betweenIfPresent("start_time", reqVO.getBeginTime(), reqVO.getEndTime());
LambdaQueryWrapperX<OperateLogDO> query = new LambdaQueryWrapperX<OperateLogDO>()
.likeIfPresent(OperateLogDO::getModule, reqVO.getModule())
.inIfPresent(OperateLogDO::getUserId, userIds)
.eqIfPresent(OperateLogDO::getType, reqVO.getType())
.betweenIfPresent(OperateLogDO::getStartTime, reqVO.getBeginTime(), reqVO.getEndTime());
if (Boolean.TRUE.equals(reqVO.getSuccess())) {
query.eq("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
query.eq(OperateLogDO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
} else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
query.gt("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
query.gt(OperateLogDO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
}
query.orderByDesc("id"); // 降序
query.orderByDesc(OperateLogDO::getId); // 降序
return selectPage(reqVO, query);
}
default List<OperateLogDO> selectList(OperateLogExportReqVO reqVO, Collection<Long> userIds) {
QueryWrapperX<OperateLogDO> query = new QueryWrapperX<OperateLogDO>()
.likeIfPresent("module", reqVO.getModule())
.inIfPresent("user_id", userIds)
.eqIfPresent("operate_type", reqVO.getType())
.betweenIfPresent("start_time", reqVO.getBeginTime(), reqVO.getEndTime());
LambdaQueryWrapperX<OperateLogDO> query = new LambdaQueryWrapperX<OperateLogDO>()
.likeIfPresent(OperateLogDO::getModule, reqVO.getModule())
.inIfPresent(OperateLogDO::getUserId, userIds)
.eqIfPresent(OperateLogDO::getType, reqVO.getType())
.betweenIfPresent(OperateLogDO::getStartTime, reqVO.getBeginTime(), reqVO.getEndTime());
if (Boolean.TRUE.equals(reqVO.getSuccess())) {
query.eq("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
query.eq(OperateLogDO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
} else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
query.gt("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
query.gt(OperateLogDO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
}
query.orderByDesc("id"); // 降序
query.orderByDesc(OperateLogDO::getId); // 降序
return selectList(query);
}

View File

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.notice;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO;
import org.apache.ibatis.annotations.Mapper;
@@ -11,9 +11,10 @@ import org.apache.ibatis.annotations.Mapper;
public interface NoticeMapper extends BaseMapperX<NoticeDO> {
default PageResult<NoticeDO> selectPage(NoticePageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<NoticeDO>()
.likeIfPresent("title", reqVO.getTitle())
.eqIfPresent("status", reqVO.getStatus()));
return selectPage(reqVO, new LambdaQueryWrapperX<NoticeDO>()
.likeIfPresent(NoticeDO::getTitle, reqVO.getTitle())
.eqIfPresent(NoticeDO::getStatus, reqVO.getStatus())
.orderByDesc(NoticeDO::getId));
}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Date;
import java.util.List;
@Mapper
public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO> {
default OAuth2AccessTokenDO selectByAccessToken(String accessToken) {
return selectOne(OAuth2AccessTokenDO::getAccessToken, accessToken);
}
default List<OAuth2AccessTokenDO> selectListByRefreshToken(String refreshToken) {
return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken);
}
default PageResult<OAuth2AccessTokenDO> selectPage(OAuth2AccessTokenPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<OAuth2AccessTokenDO>()
.eqIfPresent(OAuth2AccessTokenDO::getUserId, reqVO.getUserId())
.eqIfPresent(OAuth2AccessTokenDO::getUserType, reqVO.getUserType())
.eqIfPresent(OAuth2AccessTokenDO::getClientId, reqVO.getClientId())
.gt(OAuth2AccessTokenDO::getExpiresTime, new Date())
.orderByDesc(OAuth2AccessTokenDO::getId));
}
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface OAuth2ApproveMapper extends BaseMapperX<OAuth2ApproveDO> {
default int update(OAuth2ApproveDO updateObj) {
return update(updateObj, new LambdaQueryWrapperX<OAuth2ApproveDO>()
.eq(OAuth2ApproveDO::getUserId, updateObj.getUserId())
.eq(OAuth2ApproveDO::getUserType, updateObj.getUserType())
.eq(OAuth2ApproveDO::getClientId, updateObj.getClientId())
.eq(OAuth2ApproveDO::getScope, updateObj.getScope()));
}
default List<OAuth2ApproveDO> selectListByUserIdAndUserTypeAndClientId(Long userId, Integer userType, String clientId) {
return selectList(new LambdaQueryWrapperX<OAuth2ApproveDO>()
.eq(OAuth2ApproveDO::getUserId, userId)
.eq(OAuth2ApproveDO::getUserType, userType)
.eq(OAuth2ApproveDO::getClientId, clientId));
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.Date;
/**
* OAuth2 客户端 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface OAuth2ClientMapper extends BaseMapperX<OAuth2ClientDO> {
default PageResult<OAuth2ClientDO> selectPage(OAuth2ClientPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<OAuth2ClientDO>()
.likeIfPresent(OAuth2ClientDO::getName, reqVO.getName())
.eqIfPresent(OAuth2ClientDO::getStatus, reqVO.getStatus())
.orderByDesc(OAuth2ClientDO::getId));
}
default OAuth2ClientDO selectByClientId(String clientId) {
return selectOne(OAuth2ClientDO::getClientId, clientId);
}
@Select("SELECT COUNT(*) FROM system_oauth2_client WHERE update_time > #{maxUpdateTime}")
int selectCountByUpdateTimeGt(Date maxUpdateTime);
}

View File

@@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OAuth2CodeMapper extends BaseMapperX<OAuth2CodeDO> {
default OAuth2CodeDO selectByCode(String code) {
return selectOne(OAuth2CodeDO::getCode, code);
}
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshTokenDO> {
default int deleteByRefreshToken(String refreshToken) {
return delete(new LambdaQueryWrapperX<OAuth2RefreshTokenDO>()
.eq(OAuth2RefreshTokenDO::getRefreshToken, refreshToken));
}
default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) {
return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken);
}
}

View File

@@ -28,7 +28,7 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
.eqIfPresent(MenuDO::getStatus, reqVO.getStatus()));
}
@Select("SELECT id FROM system_menu WHERE update_time > #{maxUpdateTime} LIMIT 1")
MenuDO selectExistsByUpdateTimeAfter(Date maxUpdateTime);
@Select("SELECT COUNT(*) FROM system_menu WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(Date maxUpdateTime);
}

View File

@@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.system.dal.mysql.permission;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
@@ -19,32 +19,35 @@ import java.util.List;
public interface RoleMapper extends BaseMapperX<RoleDO> {
default PageResult<RoleDO> selectPage(RolePageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<RoleDO>().likeIfPresent("name", reqVO.getName())
.likeIfPresent("code", reqVO.getCode())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
return selectPage(reqVO, new LambdaQueryWrapperX<RoleDO>()
.likeIfPresent(RoleDO::getName, reqVO.getName())
.likeIfPresent(RoleDO::getCode, reqVO.getCode())
.eqIfPresent(RoleDO::getStatus, reqVO.getStatus())
.betweenIfPresent(BaseDO::getCreateTime, reqVO.getBeginTime(), reqVO.getEndTime())
.orderByDesc(RoleDO::getId));
}
default List<RoleDO> listRoles(RoleExportReqVO reqVO) {
return selectList(new QueryWrapperX<RoleDO>().likeIfPresent("name", reqVO.getName())
.likeIfPresent("code", reqVO.getCode())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
default List<RoleDO> selectList(RoleExportReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<RoleDO>()
.likeIfPresent(RoleDO::getName, reqVO.getName())
.likeIfPresent(RoleDO::getCode, reqVO.getCode())
.eqIfPresent(RoleDO::getStatus, reqVO.getStatus())
.betweenIfPresent(BaseDO::getCreateTime, reqVO.getBeginTime(), reqVO.getEndTime()));
}
default RoleDO selectByName(String name) {
return selectOne(new QueryWrapperX<RoleDO>().eq("name", name));
return selectOne(RoleDO::getName, name);
}
default RoleDO selectByCode(String code) {
return selectOne(new QueryWrapperX<RoleDO>().eq("code", code));
return selectOne(RoleDO::getCode, code);
}
default List<RoleDO> selectListByStatus(@Nullable Collection<Integer> statuses) {
return selectList(new LambdaQueryWrapperX<RoleDO>().inIfPresent(RoleDO::getStatus, statuses));
return selectList(RoleDO::getStatus, statuses);
}
@Select("SELECT id FROM system_role WHERE update_time > #{maxUpdateTime} LIMIT 1")
RoleDO selectExistsByUpdateTimeAfter(Date maxUpdateTime);
@Select("SELECT COUNT(*) FROM system_role WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(Date maxUpdateTime);
}

View File

@@ -11,7 +11,6 @@ import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Mapper
public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> {
@@ -37,7 +36,7 @@ public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> {
delete(new QueryWrapper<RoleMenuDO>().eq("role_id", roleId));
}
@Select("SELECT id FROM system_role_menu WHERE update_time > #{maxUpdateTime} LIMIT 1")
Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
@Select("SELECT COUNT(*) FROM system_role_menu WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(Date maxUpdateTime);
}

Some files were not shown because too many files have changed in this diff Show More