- 后端:重构 oauth2 模块,方便后续 User 接入。
- 后端:重写 Admin 安全拦截器,实现类似 Shiro 的效果。
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package cn.iocoder.mall.admin.api;
|
||||
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.admin.api.bo.role.RoleBO;
|
||||
import cn.iocoder.mall.admin.api.bo.admin.AdminAuthenticationBO;
|
||||
import cn.iocoder.mall.admin.api.bo.admin.AdminAuthorizationBO;
|
||||
import cn.iocoder.mall.admin.api.bo.admin.AdminBO;
|
||||
import cn.iocoder.mall.admin.api.bo.role.RoleBO;
|
||||
import cn.iocoder.mall.admin.api.dto.admin.*;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -14,6 +16,16 @@ import java.util.Map;
|
||||
*/
|
||||
public interface AdminService {
|
||||
|
||||
/**
|
||||
* 用户认证。认证成功后,返回认证信息
|
||||
*
|
||||
* 实际上,就是用户名 + 密码登陆
|
||||
*
|
||||
* @param adminAuthenticationDTO 用户认证信息
|
||||
* @return 认证信息
|
||||
*/
|
||||
AdminAuthenticationBO authentication(AdminAuthenticationDTO adminAuthenticationDTO);
|
||||
|
||||
PageResult<AdminBO> getAdminPage(AdminPageDTO adminPageDTO);
|
||||
|
||||
AdminBO addAdmin(Integer adminId, AdminAddDTO adminAddDTO);
|
||||
@@ -49,4 +61,13 @@ public interface AdminService {
|
||||
*/
|
||||
Boolean assignAdminRole(Integer adminId, AdminAssignRoleDTO adminAssignRoleDTO);
|
||||
|
||||
/**
|
||||
* 判断管理员是否有指定权限
|
||||
*
|
||||
* @param adminId 管理员
|
||||
* @param permissions 权限数组
|
||||
* @return 管理员授权信息
|
||||
*/
|
||||
AdminAuthorizationBO checkPermissions(Integer adminId, List<String> permissions);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
package cn.iocoder.mall.admin.api;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Oauth2 服务接口
|
||||
*/
|
||||
public interface OAuth2Service {
|
||||
|
||||
CommonResult<OAuth2AccessTokenBO> getAccessToken(String username, String password);
|
||||
|
||||
/**
|
||||
* 校验访问令牌,获取身份信息( 不包括 accessToken 等等 )
|
||||
* 根据身份信息,创建 accessToken 信息
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @return 授权信息
|
||||
* @param oauth2CreateTokenDTO 身份信息 DTO
|
||||
* @return accessToken 信息
|
||||
*/
|
||||
CommonResult<OAuth2AuthenticationBO> checkToken(String accessToken);
|
||||
|
||||
/**
|
||||
* 校验权限(鉴权)
|
||||
*
|
||||
* @param adminId 管理员编号
|
||||
* @param roleIds 管理员拥有的角色编号的集合
|
||||
* @param url 指定 URL
|
||||
* @return 是否有权限
|
||||
*/
|
||||
CommonResult<Boolean> checkPermission(Integer adminId, Set<Integer> roleIds, String url);
|
||||
OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO);
|
||||
|
||||
// TODO @see 刷新 token
|
||||
|
||||
/**
|
||||
* 通过 accessToken 获得身份信息
|
||||
*
|
||||
* @param oauth2GetTokenDTO accessToken 信息
|
||||
* @return 身份信息
|
||||
*/
|
||||
OAuth2AuthenticationBO getAuthentication(OAuth2GetTokenDTO oauth2GetTokenDTO);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.mall.admin.api.bo.admin;
|
||||
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@ApiModel("管理员认证 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AdminAuthenticationBO {
|
||||
|
||||
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty(value = "昵称", required = true, example = "小王")
|
||||
private String nickname;
|
||||
|
||||
private OAuth2AccessTokenBO token;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.mall.admin.api.bo.admin;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@ApiModel("管理员授权 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AdminAuthorizationBO {
|
||||
|
||||
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty(value = "角色编号数组", required = true, example = "1")
|
||||
private Set<Integer> roleIds;
|
||||
|
||||
}
|
||||
@@ -1,28 +1,24 @@
|
||||
package cn.iocoder.mall.admin.api.bo.oauth2;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* OAUTH2 AccessToken BO
|
||||
*/
|
||||
@ApiModel("OAuth2 Token 信息 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AccessTokenBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
@ApiModelProperty(value = "accessToken", required = true, example = "001e8f49b20e47f7b3a2de774497cd50")
|
||||
private String accessToken;
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "refreshToken", required = true, example = "001e8f49b20e47f7b3a2de774497cd50")
|
||||
private String refreshToken;
|
||||
/**
|
||||
* 过期时间,单位:秒。
|
||||
*/
|
||||
|
||||
@ApiModelProperty(value = "过期时间,单位:秒", required = true, example = "1024")
|
||||
private Integer expiresIn;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
package cn.iocoder.mall.admin.api.bo.oauth2;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* OAUTH2 认证 BO
|
||||
*/
|
||||
@ApiModel("OAUTH2 认证 BO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AuthenticationBO implements Serializable {
|
||||
public class OAuth2AuthenticationBO {
|
||||
|
||||
/**
|
||||
* 管理员编号
|
||||
*/
|
||||
private Integer adminId;
|
||||
/**
|
||||
* 角色编号数组
|
||||
*/
|
||||
private Set<Integer> roleIds;
|
||||
@ApiModelProperty(value = "用户编号", required = true, example = "1")
|
||||
private Integer userId;
|
||||
|
||||
@ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参考 UserTypeEnum 枚举")
|
||||
private Integer userType;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.mall.admin.api.bo.oauth2;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* OAUTH2 认证 BO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AuthenticationOldBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 管理员编号
|
||||
*/
|
||||
private Integer adminId;
|
||||
/**
|
||||
* 角色编号数组
|
||||
*/
|
||||
private Set<Integer> roleIds;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -12,11 +12,11 @@ public enum AdminErrorCodeEnum {
|
||||
// OAUTH2_INVALID_GRANT_BAD_CREDENTIALS(1001001001, "密码不正确"), // 暂时没用到
|
||||
// OAUTH2_INVALID_GRANT_USERNAME_NOT_FOUND(1001001002, "账号不存在"), // 暂时没用到
|
||||
// OAUTH2_INVALID_GRANT(1001001010, ""), // 预留
|
||||
OAUTH_INVALID_TOKEN_NOT_FOUND(1002001011, "访问令牌不存在"),
|
||||
OAUTH_INVALID_TOKEN_EXPIRED(1002001012, "访问令牌已过期"),
|
||||
OAUTH_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"),
|
||||
OAUTH_INVALID_PERMISSION(1002001014, "没有该操作权限"), // TODO 芋艿,临时放在 OAUTH2 模块,理论来说,OAUTH2 只做认证,不做鉴权。
|
||||
OAUTH_NOT_LOGIN(1002001015, "账号未登陆"),
|
||||
OAUTH2_INVALID_TOKEN_NOT_FOUND(1002001011, "访问令牌不存在"),
|
||||
OAUTH2_INVALID_TOKEN_EXPIRED(1002001012, "访问令牌已过期"),
|
||||
OAUTH2_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"),
|
||||
OAUTH2_NOT_LOGIN(1002001015, "账号未登陆"),
|
||||
OAUTH2_INVALID_TOKEN_ERROR_USER_TYPE(1002001016, "访问令牌用户类型不正确"),
|
||||
|
||||
OAUTH_INVALID_TOKEN(1002001020, ""), // 预留
|
||||
|
||||
@@ -29,6 +29,7 @@ public enum AdminErrorCodeEnum {
|
||||
ADMIN_DELETE_ONLY_DISABLE(1002002004, "只有关闭的账号才可以删除"),
|
||||
ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE(1002002005, "管理员的账号状态不允许变更"),
|
||||
ADMIN_ASSIGN_ROLE_NOT_EXISTS(1002002006, "分配员工角色时,有角色不存在"),
|
||||
ADMIN_INVALID_PERMISSION(1002002007, "没有该操作权限"),
|
||||
|
||||
// ========== 资源模块 1002003000 ==========
|
||||
RESOURCE_NAME_DUPLICATE(1002003000, "已经存在该名字的资源"),
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.mall.admin.api.constant;
|
||||
|
||||
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 Integer value;
|
||||
/**
|
||||
* 资源类型名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
ResourceTypeEnum(Integer value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public ResourceTypeEnum setValue(Integer value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ResourceTypeEnum setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class AdminAddDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "登陆账号", required = true, example = "15601691300")
|
||||
@NotEmpty(message = "登陆账号不能为空")
|
||||
@Length(min = 6, max = 16, message = "账号长度为 6-16 位")
|
||||
@Length(min = 5, max = 16, message = "账号长度为 5-16 位")
|
||||
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
||||
private String username;
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.mall.admin.api.dto.admin;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@ApiModel("管理员认证 DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AdminAuthenticationDTO {
|
||||
|
||||
@ApiModelProperty(value = "登陆账号", required = true, example = "15601691300")
|
||||
@NotEmpty(message = "登陆账号不能为空")
|
||||
@Length(min = 5, max = 16, message = "账号长度为 5-16 位")
|
||||
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty(value = "密码", required = true, example = "buzhidao")
|
||||
@NotEmpty(message = "密码不能为空")
|
||||
@Length(min = 6, max = 16, message = "密码长度为 6-16 位")
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public class AdminUpdateDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "登陆账号", required = true, example = "15601691300")
|
||||
@NotEmpty(message = "登陆账号不能为空")
|
||||
@Length(min = 6, max = 16, message = "账号长度为 6-16 位")
|
||||
@Length(min = 5, max = 16, message = "账号长度为 5-16 位")
|
||||
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
|
||||
private String username;
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.mall.admin.api.dto.oauth2;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.admin.api.constant.ResourceTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("OAuth2 创建 Token DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2CreateTokenDTO {
|
||||
|
||||
@ApiModelProperty(value = "用户编号", required = true, example = "1")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
|
||||
@ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 ResourceTypeEnum 枚举")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
@InEnum(value = ResourceTypeEnum.class, message = "用户类型必须是 {value}")
|
||||
private Integer userType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.mall.admin.api.dto.oauth2;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.admin.api.constant.ResourceTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("OAuth2 身份验证 DTO")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2GetTokenDTO {
|
||||
|
||||
@ApiModelProperty(value = "accessToken", required = true, example = "001e8f49b20e47f7b3a2de774497cd50")
|
||||
@NotEmpty(message = "accessToken 不能为空")
|
||||
private String accessToken;
|
||||
|
||||
@ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 ResourceTypeEnum 枚举")
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
@InEnum(value = ResourceTypeEnum.class, message = "用户类型必须是 {value}")
|
||||
private Integer userType;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.iocoder.mall.admin.api.dto.resource;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.admin.api.constant.ResourceTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -17,6 +19,7 @@ public class ResourceAddDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "资源类型。1 代表【菜单】;2 代表【按钮】", required = true, example = "1")
|
||||
@NotNull(message = "类型不能为空")
|
||||
@InEnum(value = ResourceTypeEnum.class, message = "资源类型必须是 {value}")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty(value = "排序", required = true, example = "1")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.iocoder.mall.admin.api.dto.resource;
|
||||
|
||||
import cn.iocoder.common.framework.validator.InEnum;
|
||||
import cn.iocoder.mall.admin.api.constant.ResourceTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -21,6 +23,7 @@ public class ResourceUpdateDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "资源类型。1 代表【菜单】;2 代表【按钮】", required = true, example = "1")
|
||||
@NotNull(message = "类型不能为空")
|
||||
@InEnum(value = ResourceTypeEnum.class, message = "资源类型必须是 {value}")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty(value = "排序", required = true, example = "1")
|
||||
|
||||
Reference in New Issue
Block a user