增加 auth 授权相关处理(未完成)

This commit is contained in:
YunaiV
2020-04-22 21:57:26 +08:00
parent 6f37500f62
commit a545d673ab
36 changed files with 528 additions and 54 deletions

View File

@@ -22,6 +22,7 @@
<module>system-rpc</module>
<module>system-rest</module>
<module>system-biz</module>
<module>system-biz-api</module>
</modules>
<dependencyManagement>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>system</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-biz-api</artifactId>
<dependencies>
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>common-framework</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -11,24 +11,22 @@ public enum SystemErrorCodeEnum implements ServiceExceptionUtil.Enumerable {
// ========== OAUTH2 模块 ==========
OAUTH2_UNKNOWN(1001001000, "未知错误"), // 预留
OAUTH2_ACCOUNT_NOT_FOUND(1001001001, "账号不存在"),
OAUTH2_ACCOUNT_PASSWORD_ERROR(1001001002, "密码不正确"),
OAUTH2_INVALID_TOKEN_NOT_FOUND(1002001011, "访问令牌不存在"),
OAUTH2_INVALID_TOKEN_EXPIRED(1002001012, "访问令牌已过期"),
OAUTH2_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"),
// OAUTH2_NOT_LOGIN(1002001015, "账号未登陆"),
// OAUTH_INVALID_REFRESH_TOKEN_NOT_FOUND(1002001017, "刷新令牌不存在"),
// OAUTH_INVALID_REFRESH_TOKEN_EXPIRED(1002001018, "访问令牌已过期"),
// 预留 1001001001 ~ 1001001099 错误码方便前端
OAUTH2_ACCESS_TOKEN_NOT_FOUND(1001001001, "访问令牌不存在"),
OAUTH2_ACCESS_TOKEN_TOKEN_EXPIRED(1001001002, "访问令牌已过期"),
OAUTH2_ACCESS_TOKEN_INVALID(1001001003, "访问令牌已失效"),
OAUTH2_NOT_AUTHENTICATE(1001001004, "账号未登陆"),
// 其它 1001001100 开始
OAUTH2_ACCOUNT_NOT_FOUND(1001001100, "账号不存在"),
OAUTH2_ACCOUNT_PASSWORD_ERROR(1001001101, "密码不正确"),
// ========== OAuth 手机验证码模块 ==========
OAUTH2_MOBILE_CODE_NOT_FOUND(1001001100, "验证码不存在"),
OAUTH2_MOBILE_CODE_EXPIRED(1001001101, "验证码已过期"),
OAUTH2_MOBILE_CODE_USED(1001001102, "验证码已使用"),
OAUTH2_MOBILE_CODE_NOT_CORRECT(1001001104, "验证码不正确"),
OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001001105, "超过每日短信发送数量"),
OAUTH2_MOBILE_CODE_SEND_TOO_FAST(1001001106, "短信发送过于频率"),
OAUTH2_MOBILE_CODE_NOT_FOUND(1001001200, "验证码不存在"),
OAUTH2_MOBILE_CODE_EXPIRED(1001001201, "验证码已过期"),
OAUTH2_MOBILE_CODE_USED(1001001202, "验证码已使用"),
OAUTH2_MOBILE_CODE_NOT_CORRECT(1001001203, "验证码不正确"),
OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001001204, "超过每日短信发送数量"),
OAUTH2_MOBILE_CODE_SEND_TOO_FAST(1001001205, "短信发送过于频率"),
// ========== 管理员模块 1002002000 ==========
ADMIN_NOT_FOUND(1002002000, "管理员不存在"),

View File

@@ -0,0 +1,6 @@
/**
* 该项目,主要用于暴露一些共享的枚举类等。
*
* 例如说RPC 接口提供错误码给调用方
*/
package cn.iocoder.mall.system.biz;

View File

@@ -15,7 +15,7 @@
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>common-framework</artifactId>
<artifactId>system-biz-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

View File

@@ -0,0 +1,15 @@
package cn.iocoder.mall.system.biz.bo.authorization;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 授权模块 - 授权信息 BO
*/
@Data
@Accessors(chain = true)
public class AuthorizationBO {
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.mall.system.biz.dataobject.authorization;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* {@link AccountDO} 和 {@link RoleDO} 的关联表
*/
@TableName("admin_role")
@Data
@Accessors(chain = true)
public class AccountRoleDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 账号编号
*
* 关联 {@link AccountDO#getId()}
*/
private Integer accountId;
/**
* 角色编号
*
* 关联 {@link RoleDO#getId()}
*/
private Integer roleId;
}

View File

@@ -0,0 +1,73 @@
package cn.iocoder.mall.system.biz.dataobject.authorization;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 资源实体
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName(value = "resource")
public class ResourceDO extends DeletableDO {
/**
* 资源编号
*/
private Integer id;
/**
* 菜单名
*/
private String name;
/**
* 权限标识
*
* 一般格式为:${系统}:${模块}:${操作}
* 例如说system:admin:add即 system 服务的添加管理员。
*
* 当我们把该 ResourceDO 赋予给角色后,意味着该角色有该资源:
* - 对于后端,配合 @RequiresPermissions 注解,配置 API 接口需要该权限,从而对 API 接口进行权限控制。
* - 对于前端,配合前端标签,配置按钮是否展示,避免用户没有该权限时,结果可以看到该操作。
*/
private String permission;
/**
* 资源类型
*
* 关联 {@link Resource}
*/
private Integer type;
/**
* 排序
*/
private Integer sort;
/**
* 父级资源编号
*
* 关联:{@link ResourceDO#getId()}
*/
private Integer pid;
/**
*
*
* 目前当且仅当资源类型为【菜单】时,才会生效,即 handler 配置为界面 URL ,或者前端组件名,或者前端的路由。
*/
private String handler;
/**
* 图标
*
* 目前当且仅当资源类型为【菜单】时,才会生效
*/
private String icon;
/**
* 权限标识数组,使用逗号分隔。
*
* 例如system:admin:add
* 推荐格式为 ${系统}:${模块}:${操作}
*/
private String permissions;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.mall.system.biz.dataobject.authorization;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 角色实体
*/
@TableName("role")
@Data
@Accessors(chain = true)
public class RoleDO extends DeletableDO {
/**
* 角色编号
*/
private Integer id;
/**
* 角色名
*/
private String name;
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.mall.system.biz.dataobject.authorization;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* {@link RoleDO} 和 {@link ResourceDO} 的关联表
*/
@TableName("role_resource")
@Data
@Accessors(chain = true)
public class RoleResourceDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 角色编号(外键:{@link RoleDO}
*/
private Integer roleId;
/**
* 资源编号(外键:{@link ResourceDO}
*/
private Integer resourceId;
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.mall.system.biz.dto.authorization;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* OAuth2 模块 - 访问令牌认证 Request
*/
@Data
@Accessors(chain = true)
public class AuthorizationCheckPermissionsDTO {
@NotNull(message = "访问令牌不能为空")
private String accessToken;
@NotNull(message = "IP 不能为空")
private String ip;
}

View File

@@ -0,0 +1,44 @@
package cn.iocoder.mall.system.biz.enums.authorization;
import cn.iocoder.common.framework.core.IntArrayValuable;
import java.util.Arrays;
/**
* 资源类型枚举
*/
public enum ResourceTypeEnum implements IntArrayValuable {
MENU(1, "菜单"),
BUTTON(2, "按钮");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ResourceTypeEnum::getValue).toArray();
/**
* 资源类型
*/
private final Integer value;
/**
* 资源类型名
*/
private final String name;
ResourceTypeEnum(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@@ -0,0 +1,10 @@
package cn.iocoder.mall.system.biz.service.admin;
/**
* 授权 Service 接口
*/
public class AuthorizationService {
}

View File

@@ -0,0 +1,9 @@
package cn.iocoder.mall.system.biz.service.authorization;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationCheckPermissionsDTO;
public interface AuthorizationService {
void checkPermissions(AuthorizationCheckPermissionsDTO checkPermissionsDTO);
}

View File

@@ -0,0 +1,14 @@
package cn.iocoder.mall.system.biz.service.authorization;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationCheckPermissionsDTO;
import org.springframework.stereotype.Service;
@Service
public class AuthorizationServiceImpl implements AuthorizationService {
@Override
public void checkPermissions(AuthorizationCheckPermissionsDTO checkPermissionsDTO) {
}
}

View File

@@ -0,0 +1,4 @@
package cn.iocoder.mall.system.biz.service.authorization;
public interface ResourceService {
}

View File

@@ -0,0 +1,4 @@
package cn.iocoder.mall.system.biz.service.authorization;
public interface RoleService {
}

View File

@@ -53,7 +53,7 @@ public class OAuth2ServiceImpl implements OAuth2Service {
@Override
@Transactional
public OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO authenticateDTO) {
public OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO authenticateDTO) {
// 获得账号
AccountBO accountBO = accountService.getByUsername(authenticateDTO.getUsername());
if (accountBO == null) {
@@ -101,13 +101,13 @@ public class OAuth2ServiceImpl implements OAuth2Service {
public OAuth2AccessTokenBO authenticate(OAuth2AccessTokenAuthenticateDTO authenticateDTO) {
OAuth2AccessTokenDO oauth2AccessTokenDO = oauth2AccessTokenMapper.selectById(authenticateDTO.getAccessToken());
if (oauth2AccessTokenDO == null) { // 不存在
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_INVALID_TOKEN_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_ACCESS_TOKEN_NOT_FOUND.getCode());
}
if (oauth2AccessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_INVALID_TOKEN_EXPIRED.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_ACCESS_TOKEN_TOKEN_EXPIRED.getCode());
}
if (!oauth2AccessTokenDO.getValid()) { // 无效
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_INVALID_TOKEN_INVALID.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_ACCESS_TOKEN_INVALID.getCode());
}
// 转换返回
return OAuth2Convert.INSTANCE.convert(oauth2AccessTokenDO);

View File

@@ -3,6 +3,7 @@ package cn.iocoder.mall.system.rest.controller.oauth2;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.security.core.annotation.RequiresNone;
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
@@ -31,7 +32,8 @@ public class AdminsOAuth2Controller {
private AdminService adminService;
@PostMapping("/username-authenticate")
@ApiOperation("用户名认证")
@ApiOperation("用户名认证(登陆)")
@RequiresNone
public CommonResult<AdminsOAuth2AuthenticateResponse> usernameAuthenticate(AdminsOAuth2UsernameAuthenticateRequest request) {
// 执行认证
OAuth2UsernameAuthenticateDTO authenticateDTO = AdminsOAuth2Convert.INSTANCE.convert(request);

View File

@@ -3,6 +3,7 @@ package cn.iocoder.mall.system.rest.controller.oauth2;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.security.core.annotation.RequiresNone;
import cn.iocoder.mall.system.biz.bo.user.UserAuthenticateBO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
@@ -37,6 +38,7 @@ public class UsersOAuth2Controller {
@PostMapping("/mobile-code-authenticate")
@ApiOperation("手机验证码认证")
@RequiresNone
public CommonResult<UsersOAuth2AuthenticateResponse> mobileCodeAuthenticate(UsersOAuth2MobileCodeAuthenticateRequest request,
HttpServletRequest httpRequest) {
// 执行认证
@@ -52,6 +54,7 @@ public class UsersOAuth2Controller {
@PostMapping("/send-mobile-code")
@ApiOperation("发送手机验证码")
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691234")
@RequiresNone
public CommonResult<Boolean> sendMobileCode(@RequestParam("mobile") String mobile,
HttpServletRequest request) {
// 执行发送验证码

View File

@@ -15,7 +15,7 @@
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>common-framework</artifactId>
<artifactId>system-biz-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

View File

@@ -0,0 +1,7 @@
package cn.iocoder.mall.system.rpc.api.admin;
/**
* Admin RPC 接口
*/
public interface AdminRPC {
}

View File

@@ -4,6 +4,9 @@ import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.system.rpc.request.oauth2.OAuth2AccessTokenAuthenticateRequest;
import cn.iocoder.mall.system.rpc.response.oauth2.OAuth2AccessTokenResponse;
/**
* OAuth2 RPC 接口
*/
public interface OAuth2RPC {
CommonResult<OAuth2AccessTokenResponse> authenticate(OAuth2AccessTokenAuthenticateRequest request);

View File

@@ -0,0 +1,21 @@
package cn.iocoder.mall.system.rpc.request.authorization;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 鉴权模块 - 校验账号是否有权限 Request
*/
@Data
@Accessors(chain = true)
public class AuthorizationCheckPermissionsRequest {
@NotNull(message = "账号不能为空")
private Integer accountId;
@NotNull(message = "校验的权限不能为空")
private List<String> permissions;
}

View File

@@ -6,7 +6,7 @@ import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* OAuth2 访问令牌认证 Request
* OAuth2 模块 - 访问令牌认证 Request
*/
@Data
@Accessors(chain = true)

View File

@@ -0,0 +1,19 @@
package cn.iocoder.mall.system.rpc.response.admin;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* Admin 信息 Response
*/
@Data
@Accessors(chain = true)
public class AdminResponse {
/**
* 管理员编号
*/
private Integer id;
// private String
}