diff --git a/ecell-internationalize/ecell-internationalize-auth/pom.xml b/ecell-internationalize/ecell-internationalize-auth/pom.xml
new file mode 100644
index 0000000..a472697
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+ ecell-internationalize
+ com.ecell.internationalize
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ com.ecell.internationalize.auth
+ ecell-internationalize-auth
+
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger.fox.version}
+
+
+ com.ecell.internationalize.common.swagger
+ ecell-internationalize-swagger
+ 1.0-SNAPSHOT
+
+
+ com.ecell.internationalize.common.core
+ ecell-internationalize-core
+ 1.0-SNAPSHOT
+
+
+
+ com.ecell.internationalize.common.security
+ ecell-internationalize-security
+ 1.0-SNAPSHOT
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/EcellAuthApplication.java b/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/EcellAuthApplication.java
new file mode 100644
index 0000000..dd4dfe7
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/EcellAuthApplication.java
@@ -0,0 +1,27 @@
+package com.ecell.internationalize.auth;
+
+import com.ecell.internationalize.auth.config.ExceptionAdviceConfig;
+import com.ecell.internationalize.common.core.utils.SpringUtils;
+import com.ecell.internationalize.common.swagger.annotation.EnableCustomSwagger2;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * @author borui
+ */
+
+@EnableFeignClients
+@EnableCustomSwagger2
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class },scanBasePackages = {"com.ecell.internationalize"})
+public class EcellAuthApplication {
+ public static void main(String[] args)
+ {
+ SpringApplication.run(EcellAuthApplication.class, args);
+
+
+ System.out.println("(♥◠‿◠)ノ゙ 认证授权中心启动成功 ლ(´ڡ`ლ)゙ \n");
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/config/ExceptionAdviceConfig.java b/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/config/ExceptionAdviceConfig.java
new file mode 100644
index 0000000..49dfcc6
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/config/ExceptionAdviceConfig.java
@@ -0,0 +1,40 @@
+package com.ecell.internationalize.auth.config;
+
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.SpringUtils;
+import com.ecell.internationalize.common.core.utils.locale.LocaleUtil;
+import com.ecell.internationalize.common.core.web.domain.AjaxResult;
+import net.bytebuddy.implementation.bytecode.constant.FieldConstant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.MessageSource;
+import org.springframework.http.HttpRequest;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.Locale;
+
+/**
+ * @author borui
+ */
+@RestControllerAdvice
+public class ExceptionAdviceConfig {
+ private static final Logger logger = LoggerFactory.getLogger(ExceptionAdviceConfig.class);
+ /**
+ * 全局异常处理,配置国际化
+ * @Author: liy
+ * @Date: 2022/7/8 13:53
+ */
+ @ExceptionHandler(Exception.class)
+ public AjaxResult exceptionHandler(Exception e) {
+ e.printStackTrace();
+
+// Locale locale = LocaleUtil.getLocale();
+//
+// MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
+// String message = messageSource.getMessage("messages.login.empty", null, locale);
+ String message = LocaleUtil.getMessage("messages.login.empty");
+ System.out.println("获取到的国际化语言是:=="+message);
+ return AjaxResult.error(message);
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/controller/AuthController.java b/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/controller/AuthController.java
new file mode 100644
index 0000000..a3d484c
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/java/com/ecell/internationalize/auth/controller/AuthController.java
@@ -0,0 +1,20 @@
+package com.ecell.internationalize.auth.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author borui
+ */
+@RestController
+@RequestMapping("/auth")
+public class AuthController {
+
+ @GetMapping("test")
+ public String test( ){
+ int a=1;
+ int b= a/0;
+ return "111";
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/resources/application-dev.yml b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..eca5750
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/application-dev.yml
@@ -0,0 +1,33 @@
+spring:
+ redis:
+ host: 120.77.209.176
+ port: 6379
+ database: 2
+ password: Ecell...20201001
+ # 配置国际化资源文件路径
+ messages:
+ basename: i18n/messages
+ encoding: UTF-8
+ #设置静态资源路径,多个以逗号分隔
+ web:
+ resources:
+ static-locations: classpath:static/
+mybatis:
+ #配置SQL映射文件路径
+ mapper-locations: classpath:mapper/*.xml
+ # 搜索指定包别名
+ typeAliasesPackage: com.yisai.auth
+ #驼峰命名
+ configuration:
+ map-underscore-to-camel-case: true
+#开启熔断降级
+feign:
+ sentinel:
+ enabled: true
+ client:
+ config:
+ default:
+ connectTimeout: 10000
+ readTimeout: 60000
+
+
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/resources/bootstrap.yml b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..848ce9f
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/bootstrap.yml
@@ -0,0 +1,25 @@
+# Tomcat
+server:
+ port: 9998
+
+# Spring
+spring:
+ application:
+ # 应用名称
+ name: ecell-internationalize-auth
+ profiles:
+ # 环境配置
+ active: dev
+ cloud:
+ nacos:
+ discovery:
+ # 服务注册地址
+ server-addr: 127.0.0.1:8848
+ config:
+ # 配置中心地址
+ server-addr: 127.0.0.1:8848
+ # 配置文件格式
+ file-extension: yml
+ # 共享配置
+ shared-configs:
+ - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages.properties b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..22fd134
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages.properties
@@ -0,0 +1,8 @@
+messages.login.empty=账号或者密码不能为空
+messages.fallback.info=服务不存在或网络端口错误
+messages.login.error=用户名不存在
+messages.account.delete=您的账号已被删除
+messages.account.stop=您的账号已被禁用
+messages.success=操作成功
+messages.error=操作失败,请联系管理员处理
+messages.error.password=输入的密码错误
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_en_US.properties b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_en_US.properties
new file mode 100644
index 0000000..4281241
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_en_US.properties
@@ -0,0 +1,8 @@
+messages.login.empty=Account or password cannot be empty
+messages.fallback.info=Service does not exist or network port error
+messages.login.error=user name does not exist
+messages.account.delete=Your account has been deleted
+messages.account.stop=Your account has been disabled
+messages.success=Operation successful
+messages.error=Operation failed, please contact the administrator for handling
+messages.error.password=Wrong password entered
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_ru_RU.properties b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_ru_RU.properties
new file mode 100644
index 0000000..1b997a4
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_ru_RU.properties
@@ -0,0 +1,8 @@
+messages.fallback.info=\u0421\u0435\u0440\u0432\u0438\u0441\u044B \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0442 \u0438\u043B\u0438 \u043E\u0448\u0438\u0431\u043A\u0438 \u0441\u0435\u0442\u0435\u0432\u044B\u0445 \u043F\u043E\u0440\u0442\u043E\u0432
+messages.login.error=\u0418\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
+messages.account.stop=\u0412\u0430\u0448 \u0430\u043A\u043A\u0430\u0443\u043D\u0442 \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D
+messages.error.password=\u0412\u0432\u0435\u0434\u0435\u043D\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043A\u043E\u0434\u0435
+messages.success=\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0430.
+messages.account.delete=\u0412\u0430\u0448 \u0430\u043A\u043A\u0430\u0443\u043D\u0442 \u0431\u044B\u043B \u0443\u0434\u0430\u043B\u0435\u043D
+messages.login.empty=\u041D\u043E\u043C\u0435\u0440 \u0441\u0447\u0435\u0442\u0430 \u0438\u043B\u0438 \u043F\u0430\u0440\u043E\u043B\u044C \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\u0442\u044B\u043C
+messages.error=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C
diff --git a/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_zh_CN.properties b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_zh_CN.properties
new file mode 100644
index 0000000..22fd134
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-auth/src/main/resources/i18n/messages_zh_CN.properties
@@ -0,0 +1,8 @@
+messages.login.empty=账号或者密码不能为空
+messages.fallback.info=服务不存在或网络端口错误
+messages.login.error=用户名不存在
+messages.account.delete=您的账号已被删除
+messages.account.stop=您的账号已被禁用
+messages.success=操作成功
+messages.error=操作失败,请联系管理员处理
+messages.error.password=输入的密码错误
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/pom.xml b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/pom.xml
index 8922171..3b6ca49 100644
--- a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/pom.xml
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/pom.xml
@@ -120,6 +120,13 @@
swagger-annotations
+
+
+ org.projectlombok
+ lombok
+ true
+
+
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/LoginUser.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/LoginUser.java
new file mode 100644
index 0000000..3288acf
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/LoginUser.java
@@ -0,0 +1,59 @@
+package com.ecell.internationalize.common.core.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * @author borui
+ */
+@Data
+public class LoginUser implements Serializable {
+ private static final long serialVersionUID = 1L;
+ /**
+ * 用户唯一标识
+ */
+ private String token;
+
+ /**
+ * 用户名id
+ */
+ private Long userid;
+
+ /**
+ * 用户名
+ */
+ private String username;
+
+ /**
+ * 登录时间
+ */
+ private Long loginTime;
+
+ /**
+ * 过期时间
+ */
+ private Long expireTime;
+
+ /**
+ * 登录IP地址
+ */
+ private String ipaddr;
+
+ /**
+ * 权限列表
+ */
+ private Set permissions;
+
+ /**
+ * 角色列表
+ */
+ private Set roles;
+
+ /**
+ * 用户信息
+ */
+ private SysUser sysUser;
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/SysRole.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/SysRole.java
new file mode 100644
index 0000000..352c9fa
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/SysRole.java
@@ -0,0 +1,60 @@
+package com.ecell.internationalize.common.core.domain;
+
+import com.ecell.internationalize.common.core.annotation.Excel;
+import com.ecell.internationalize.common.core.web.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * @author borui
+ */
+@Data
+public class SysRole extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 角色ID */
+ @Excel(name = "角色序号", cellType = Excel.ColumnType.NUMERIC)
+ private Long roleId;
+
+ /** 角色名称 */
+ @Excel(name = "角色名称")
+ private String roleName;
+
+ /** 角色权限 */
+ @Excel(name = "角色权限")
+ private String roleKey;
+
+ /** 角色排序 */
+ @Excel(name = "角色排序")
+ private String roleSort;
+
+ /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */
+ @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+ private String dataScope;
+
+ /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */
+ private boolean menuCheckStrictly;
+
+ /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */
+ private boolean deptCheckStrictly;
+
+ /** 角色状态(0正常 1停用) */
+ @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /** 删除标志(0代表存在 2代表删除) */
+ private String delFlag;
+
+ /** 用户是否存在此角色标识 默认不存在 */
+ private boolean flag = false;
+
+ /** 菜单组 */
+ private Long[] menuIds;
+
+ /** 部门组(数据权限) */
+ private Long[] deptIds;
+
+ public SysRole()
+ {
+
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/SysUser.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/SysUser.java
new file mode 100644
index 0000000..b054d59
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/domain/SysUser.java
@@ -0,0 +1,98 @@
+package com.ecell.internationalize.common.core.domain;
+
+import com.ecell.internationalize.common.core.annotation.Excel;
+import com.ecell.internationalize.common.core.annotation.Excels;
+import com.ecell.internationalize.common.core.web.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author borui
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "SysUser对象", description = "系统用户")
+public class SysUser extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 用户ID */
+ @Excel(name = "用户序号", cellType = Excel.ColumnType.NUMERIC, prompt = "用户编号")
+ private Long userId;
+
+ /** 部门ID */
+ @Excel(name = "部门编号", type = Excel.Type.IMPORT)
+ private Long deptId;
+
+ /** 用户账号 */
+ @Excel(name = "登录名称")
+ private String userName;
+
+ /** 用户昵称 */
+ @Excel(name = "用户名称")
+ private String nickName;
+
+ /** 用户邮箱 */
+ @Excel(name = "用户邮箱")
+ private String email;
+
+ /** 手机号码 */
+ @Excel(name = "手机号码")
+ private String phonenumber;
+
+ /** 用户性别 */
+ @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+ private String sex;
+
+ /** 用户头像 */
+ private String avatar;
+
+ /** 密码 */
+ private String password;
+
+ /** 帐号状态(0正常 1停用) */
+ @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /** 删除标志(0代表存在 2代表删除) */
+ private String delFlag;
+
+ /** 最后登录IP */
+ @Excel(name = "最后登录IP", type = Excel.Type.EXPORT)
+ private String loginIp;
+
+ /** 最后登录时间 */
+ @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
+ private Date loginDate;
+
+ /** 部门对象 */
+ @Excels({
+ @Excel(name = "部门名称", targetAttr = "deptName", type = Excel.Type.EXPORT),
+ @Excel(name = "部门负责人", targetAttr = "leader", type = Excel.Type.EXPORT)
+ })
+
+ /** 角色对象 */
+ private List roles;
+
+ /** 角色组 */
+ private Long[] roleIds;
+
+ /** 岗位组 */
+ private Long[] postIds;
+
+ /** 角色ID */
+ private Long roleId;
+
+ public SysUser()
+ {
+
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/enums/UserStatus.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/enums/UserStatus.java
index de741f7..03926f5 100644
--- a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/enums/UserStatus.java
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/enums/UserStatus.java
@@ -5,23 +5,23 @@ package com.ecell.internationalize.common.core.enums;
* @author borui
*/
public class UserStatus {
- OK("0", "正常"),DISABLE("1", "停用"),DELETED("2", "删除");
- private final String code;
- private final String info;
-
- UserStatus(String code, String info)
- {
- this.code = code;
- this.info = info;
- }
-
- public String getCode()
- {
- return code;
- }
-
- public String getInfo()
- {
- return info;
- }
+// OK("0", "正常"),DISABLE("1", "停用"),DELETED("2", "删除");
+// private final String code;
+// private final String info;
+//
+// UserStatus(String code, String info)
+// {
+// this.code = code;
+// this.info = info;
+// }
+//
+// public String getCode()
+// {
+// return code;
+// }
+//
+// public String getInfo()
+// {
+// return info;
+// }
}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/utils/locale/LocaleUtil.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/utils/locale/LocaleUtil.java
index 8ee49bd..3a76b94 100644
--- a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/utils/locale/LocaleUtil.java
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/java/com/ecell/internationalize/common/core/utils/locale/LocaleUtil.java
@@ -1,6 +1,10 @@
package com.ecell.internationalize.common.core.utils.locale;
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.SpringUtils;
import com.ecell.internationalize.common.core.utils.StringUtils;
+import org.springframework.context.MessageSource;
+import org.springframework.http.HttpRequest;
import java.util.Locale;
@@ -8,13 +12,16 @@ import java.util.Locale;
* @author borui
*/
public class LocaleUtil {
- public static Locale getLocale(String lang){
+
+ public static Locale getLocale(){
+ String language = ServletUtils.getHeader(ServletUtils.getRequest(), "content-language");
+
Locale locale;
- if (StringUtils.isEmpty(lang)) {
+ if (StringUtils.isEmpty(language)) {
locale = Locale.US;
} else {
try {
- String [] split = lang.split("_");
+ String [] split = language.split("_");
locale = new Locale(split[0], split[1]);
} catch (Exception e) {
locale = Locale.US;
@@ -22,4 +29,11 @@ public class LocaleUtil {
}
return locale;
}
+
+ public static String getMessage(String code) {
+ Locale locale = getLocale();
+ return SpringUtils.getBean(MessageSource.class).getMessage(code, null, locale);
+
+ }
+
}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/resources/META-INF/spring.factories b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/resources/META-INF/spring.factories
index ff50205..bcd4116 100644
--- a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/resources/META-INF/spring.factories
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-core/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.ruoyi.common.core.utils.SpringUtils
+ com.ecell.internationalize.common.core.utils.SpringUtils
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/pom.xml b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/pom.xml
index 3b57ea8..f6b1cfb 100644
--- a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/pom.xml
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/pom.xml
@@ -12,9 +12,23 @@
com.ecell.internationalize.common.security
ecell-internationalize-security
-
- 8
- 8
-
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ com.ecell.internationalize.common.redis
+ ecell-internationalize-redis
+ 1.0-SNAPSHOT
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/EnableCustomConfig.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/EnableCustomConfig.java
new file mode 100644
index 0000000..05dae41
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/EnableCustomConfig.java
@@ -0,0 +1,29 @@
+package com.ecell.internationalize.common.security.annotation;
+
+import com.ecell.internationalize.common.security.config.ApplicationConfig;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.cloud.openfeign.FeignAutoConfiguration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.context.annotation.Import;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import java.lang.annotation.*;
+
+/**
+ * @author borui
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+// 表示通过aop框架暴露该代理对象,AopContext能够访问
+@EnableAspectJAutoProxy(exposeProxy = true)
+// 指定要扫描的Mapper类的包的路径
+@MapperScan("com.campus.**.mapper")
+// 开启线程异步执行
+@EnableAsync
+// 自动加载类
+@Import({ ApplicationConfig.class, FeignAutoConfiguration.class })
+public @interface EnableCustomConfig {
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/InnerAuth.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/InnerAuth.java
new file mode 100644
index 0000000..c852588
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/InnerAuth.java
@@ -0,0 +1,16 @@
+package com.ecell.internationalize.common.security.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author borui
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface InnerAuth {
+ /**
+ * 是否校验用户信息
+ */
+ boolean isUser() default false;
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/Logical.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/Logical.java
new file mode 100644
index 0000000..2d65b35
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/Logical.java
@@ -0,0 +1,18 @@
+package com.ecell.internationalize.common.security.annotation;
+
+/**
+ * @author borui
+ */
+
+public enum Logical {
+ /**
+ * 必须具有所有的元素
+ */
+ AND,
+
+ /**
+ * 只需具有其中一个元素
+ */
+ OR
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresLogin.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresLogin.java
new file mode 100644
index 0000000..5cac6d1
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresLogin.java
@@ -0,0 +1,15 @@
+package com.ecell.internationalize.common.security.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author borui
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD, ElementType.TYPE })
+public @interface RequiresLogin {
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresPermissions.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresPermissions.java
new file mode 100644
index 0000000..87416b8
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresPermissions.java
@@ -0,0 +1,23 @@
+package com.ecell.internationalize.common.security.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author borui
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD, ElementType.TYPE })
+public @interface RequiresPermissions {
+ /**
+ * 需要校验的权限码
+ */
+ String[] value() default {};
+
+ /**
+ * 验证模式:AND | OR,默认AND
+ */
+ Logical logical() default Logical.AND;
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresRoles.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresRoles.java
new file mode 100644
index 0000000..6e5e6c5
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/annotation/RequiresRoles.java
@@ -0,0 +1,23 @@
+package com.ecell.internationalize.common.security.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author borui
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD, ElementType.TYPE })
+public @interface RequiresRoles {
+ /**
+ * 需要校验的角色标识
+ */
+ String[] value() default {};
+
+ /**
+ * 验证逻辑:AND | OR,默认AND
+ */
+ Logical logical() default Logical.AND;
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/aspect/InnerAuthAspect.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/aspect/InnerAuthAspect.java
new file mode 100644
index 0000000..7d363c3
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/aspect/InnerAuthAspect.java
@@ -0,0 +1,44 @@
+package com.ecell.internationalize.common.security.aspect;
+
+import com.ecell.internationalize.common.core.constant.SecurityConstants;
+import com.ecell.internationalize.common.core.exception.InnerAuthException;
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import com.ecell.internationalize.common.security.annotation.InnerAuth;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author borui
+ */
+@Aspect
+@Component
+public class InnerAuthAspect implements Ordered {
+ @Around("@annotation(innerAuth)")
+ public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable
+ {
+ String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE);
+ // 内部请求验证
+ if (!StringUtils.equals(SecurityConstants.INNER, source))
+ {
+ throw new InnerAuthException("没有内部访问权限,不允许访问");
+ }
+
+ String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID);
+ String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME);
+ // 用户信息验证
+ if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)))
+ {
+ throw new InnerAuthException("没有设置用户信息,不允许访问 ");
+ }
+ return point.proceed();
+ }
+
+ @Override
+ public int getOrder() {
+ return Ordered.HIGHEST_PRECEDENCE + 1;
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/aspect/PreAuthorizeAspect.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/aspect/PreAuthorizeAspect.java
new file mode 100644
index 0000000..401f173
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/aspect/PreAuthorizeAspect.java
@@ -0,0 +1,89 @@
+package com.ecell.internationalize.common.security.aspect;
+
+import com.ecell.internationalize.common.security.annotation.RequiresLogin;
+import com.ecell.internationalize.common.security.annotation.RequiresPermissions;
+import com.ecell.internationalize.common.security.annotation.RequiresRoles;
+import com.ecell.internationalize.common.security.auth.AuthUtil;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author borui
+ */
+@Aspect
+@Component
+public class PreAuthorizeAspect {
+ /**
+ * 定义AOP签名 (切入所有使用鉴权注解的方法)
+ */
+ public static final String POINTCUT_SIGN = " @annotation(com.ecell.internationalize.common.security.annotation.RequiresLogin) || "
+ + "@annotation(com.ecell.internationalize.common.security.annotation.RequiresPermissions) || "
+ + "@annotation(com.ecell.internationalize.common.security.annotation.RequiresRoles)";
+
+ /**
+ * 声明AOP签名
+ */
+ @Pointcut(POINTCUT_SIGN)
+ public void pointcut() {
+ }
+
+ /**
+ * 环绕切入
+ *
+ * @param joinPoint 切面对象
+ * @return 底层方法执行后的返回值
+ * @throws Throwable 底层方法抛出的异常
+ */
+ @Around("pointcut()")
+ public Object around(ProceedingJoinPoint joinPoint) throws Throwable
+ {
+ // 注解鉴权
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ checkMethodAnnotation(signature.getMethod());
+ try
+ {
+ // 执行原有逻辑
+ Object obj = joinPoint.proceed();
+ return obj;
+ }
+ catch (Throwable e)
+ {
+ throw e;
+ }
+ }
+
+
+ /**
+ * 对一个Method对象进行注解检查
+ */
+ public void checkMethodAnnotation(Method method)
+ {
+ // 校验 @RequiresLogin 注解
+ RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class);
+ if (requiresLogin != null)
+ {
+ AuthUtil.checkLogin();
+ }
+
+ // 校验 @RequiresRoles 注解
+ RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
+ if (requiresRoles != null)
+ {
+ AuthUtil.checkRole(requiresRoles);
+ }
+
+ // 校验 @RequiresPermissions 注解
+ RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
+ if (requiresPermissions != null)
+ {
+ AuthUtil.checkPermi(requiresPermissions);
+ }
+ }
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/auth/AuthLogic.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/auth/AuthLogic.java
new file mode 100644
index 0000000..ae39784
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/auth/AuthLogic.java
@@ -0,0 +1,371 @@
+package com.ecell.internationalize.common.security.auth;
+
+import com.ecell.internationalize.common.core.domain.LoginUser;
+import com.ecell.internationalize.common.core.domain.SysUser;
+import com.ecell.internationalize.common.core.exception.auth.NotLoginException;
+import com.ecell.internationalize.common.core.exception.auth.NotPermissionException;
+import com.ecell.internationalize.common.core.exception.auth.NotRoleException;
+import com.ecell.internationalize.common.core.utils.SpringUtils;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import com.ecell.internationalize.common.security.annotation.Logical;
+import com.ecell.internationalize.common.security.annotation.RequiresLogin;
+import com.ecell.internationalize.common.security.annotation.RequiresPermissions;
+import com.ecell.internationalize.common.security.annotation.RequiresRoles;
+import com.ecell.internationalize.common.security.service.TokenService;
+import com.ecell.internationalize.common.security.utils.SecurityUtils;
+import org.springframework.util.PatternMatchUtils;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author borui
+ */
+
+public class AuthLogic {
+ /** 所有权限标识 */
+ private static final String ALL_PERMISSION = "*:*:*";
+
+ /** 管理员角色权限标识 */
+ private static final String SUPER_ADMIN = "admin";
+
+ public TokenService tokenService = SpringUtils.getBean(TokenService.class);
+
+ /**
+ * 会话注销
+ */
+ public void logout()
+ {
+ String token = SecurityUtils.getToken();
+ if (token == null)
+ {
+ return;
+ }
+ logoutByToken(token);
+ }
+
+ /**
+ * 会话注销,根据指定Token
+ */
+ public void logoutByToken(String token)
+ {
+ tokenService.delLoginUser(token);
+ }
+
+ /**
+ * 检验用户是否已经登录,如未登录,则抛出异常
+ */
+ public void checkLogin()
+ {
+ getLoginUser();
+ }
+
+ /**
+ * 获取当前用户缓存信息, 如果未登录,则抛出异常
+ *
+ * @return 用户缓存信息
+ */
+ public LoginUser getLoginUser()
+ {
+ String token = SecurityUtils.getToken();
+ if (token == null)
+ {
+ throw new NotLoginException("未提供token");
+ }
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ if (loginUser == null)
+ {
+ throw new NotLoginException("无效的token");
+ }
+ return loginUser;
+ }
+
+ /**
+ * 获取当前用户缓存信息, 如果未登录,则抛出异常
+ *
+ * @param token 前端传递的认证信息
+ * @return 用户缓存信息
+ */
+ public LoginUser getLoginUser(String token)
+ {
+ return tokenService.getLoginUser(token);
+ }
+
+ /**
+ * 验证当前用户有效期, 如果相差不足120分钟,自动刷新缓存
+ *
+ * @param loginUser 当前用户信息
+ */
+ public void verifyLoginUserExpire(LoginUser loginUser)
+ {
+ tokenService.verifyToken(loginUser);
+ }
+
+ /**
+ * 验证用户是否具备某权限
+ *
+ * @param permission 权限字符串
+ * @return 用户是否具备某权限
+ */
+ public boolean hasPermi(String permission)
+ {
+ return hasPermi(getPermiList(), permission);
+ }
+
+ /**
+ * 验证用户是否具备某权限, 如果验证未通过,则抛出异常: NotPermissionException
+ *
+ * @param permission 权限字符串
+ * @return 用户是否具备某权限
+ */
+ public void checkPermi(String permission)
+ {
+ if (!hasPermi(getPermiList(), permission))
+ {
+ throw new NotPermissionException(permission);
+ }
+ }
+
+ /**
+ * 根据注解(@RequiresPermissions)鉴权, 如果验证未通过,则抛出异常: NotPermissionException
+ *
+ * @param requiresPermissions 注解对象
+ */
+ public void checkPermi(RequiresPermissions requiresPermissions)
+ {
+ if (requiresPermissions.logical() == Logical.AND)
+ {
+ checkPermiAnd(requiresPermissions.value());
+ }
+ else
+ {
+ checkPermiOr(requiresPermissions.value());
+ }
+ }
+
+ /**
+ * 验证用户是否含有指定权限,必须全部拥有
+ *
+ * @param permissions 权限列表
+ */
+ public void checkPermiAnd(String... permissions)
+ {
+ Set permissionList = getPermiList();
+ for (String permission : permissions)
+ {
+ if (!hasPermi(permissionList, permission))
+ {
+ throw new NotPermissionException(permission);
+ }
+ }
+ }
+
+ /**
+ * 验证用户是否含有指定权限,只需包含其中一个
+ *
+ * @param permissions 权限码数组
+ */
+ public void checkPermiOr(String... permissions)
+ {
+ Set permissionList = getPermiList();
+ for (String permission : permissions)
+ {
+ if (hasPermi(permissionList, permission))
+ {
+ return;
+ }
+ }
+ if (permissions.length > 0)
+ {
+ throw new NotPermissionException(permissions);
+ }
+ }
+
+ /**
+ * 判断用户是否拥有某个角色
+ *
+ * @param role 角色标识
+ * @return 用户是否具备某角色
+ */
+ public boolean hasRole(String role)
+ {
+ return hasRole(getRoleList(), role);
+ }
+
+ /**
+ * 判断用户是否拥有某个角色, 如果验证未通过,则抛出异常: NotRoleException
+ *
+ * @param role 角色标识
+ */
+ public void checkRole(String role)
+ {
+ if (!hasRole(role))
+ {
+ throw new NotRoleException(role);
+ }
+ }
+
+ /**
+ * 根据注解(@RequiresRoles)鉴权
+ *
+ * @param requiresRoles 注解对象
+ */
+ public void checkRole(RequiresRoles requiresRoles)
+ {
+ if (requiresRoles.logical() == Logical.AND)
+ {
+ checkRoleAnd(requiresRoles.value());
+ }
+ else
+ {
+ checkRoleOr(requiresRoles.value());
+ }
+ }
+
+ /**
+ * 验证用户是否含有指定角色,必须全部拥有
+ *
+ * @param roles 角色标识数组
+ */
+ public void checkRoleAnd(String... roles)
+ {
+ Set roleList = getRoleList();
+ for (String role : roles)
+ {
+ if (!hasRole(roleList, role))
+ {
+ throw new NotRoleException(role);
+ }
+ }
+ }
+
+ /**
+ * 验证用户是否含有指定角色,只需包含其中一个
+ *
+ * @param roles 角色标识数组
+ */
+ public void checkRoleOr(String... roles)
+ {
+ Set roleList = getRoleList();
+ for (String role : roles)
+ {
+ if (hasRole(roleList, role))
+ {
+ return;
+ }
+ }
+ if (roles.length > 0)
+ {
+ throw new NotRoleException(roles);
+ }
+ }
+
+ /**
+ * 根据注解(@RequiresLogin)鉴权
+ *
+ * @param at 注解对象
+ */
+ public void checkByAnnotation(RequiresLogin at)
+ {
+ this.checkLogin();
+ }
+
+ /**
+ * 根据注解(@RequiresRoles)鉴权
+ *
+ * @param at 注解对象
+ */
+ public void checkByAnnotation(RequiresRoles at)
+ {
+ String[] roleArray = at.value();
+ if (at.logical() == Logical.AND)
+ {
+ this.checkRoleAnd(roleArray);
+ }
+ else
+ {
+ this.checkRoleOr(roleArray);
+ }
+ }
+
+ /**
+ * 根据注解(@RequiresPermissions)鉴权
+ *
+ * @param at 注解对象
+ */
+ public void checkByAnnotation(RequiresPermissions at)
+ {
+ String[] permissionArray = at.value();
+ if (at.logical() == Logical.AND)
+ {
+ this.checkPermiAnd(permissionArray);
+ }
+ else
+ {
+ this.checkPermiOr(permissionArray);
+ }
+ }
+
+ /**
+ * 获取当前账号的角色列表
+ *
+ * @return 角色列表
+ */
+ public Set getRoleList()
+ {
+ try
+ {
+ LoginUser loginUser = getLoginUser();
+ return loginUser.getRoles();
+ }
+ catch (Exception e)
+ {
+ return new HashSet<>();
+ }
+ }
+
+ /**
+ * 获取当前账号的权限列表
+ *
+ * @return 权限列表
+ */
+ public Set getPermiList()
+ {
+ try
+ {
+ LoginUser loginUser = getLoginUser();
+ return loginUser.getPermissions();
+ }
+ catch (Exception e)
+ {
+ return new HashSet<>();
+ }
+ }
+
+ /**
+ * 判断是否包含权限
+ *
+ * @param authorities 权限列表
+ * @param permission 权限字符串
+ * @return 用户是否具备某权限
+ */
+ public boolean hasPermi(Collection authorities, String permission)
+ {
+ return authorities.stream().filter(StringUtils::hasText)
+ .anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission));
+ }
+
+ /**
+ * 判断是否包含角色
+ *
+ * @param roles 角色列表
+ * @param role 角色
+ * @return 用户是否具备某角色权限
+ */
+ public boolean hasRole(Collection roles, String role)
+ {
+ return roles.stream().filter(StringUtils::hasText)
+ .anyMatch(x -> SUPER_ADMIN.contains(x) || PatternMatchUtils.simpleMatch(x, role));
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/auth/AuthUtil.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/auth/AuthUtil.java
new file mode 100644
index 0000000..33ea8b4
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/auth/AuthUtil.java
@@ -0,0 +1,161 @@
+package com.ecell.internationalize.common.security.auth;
+
+import com.ecell.internationalize.common.core.domain.LoginUser;
+import com.ecell.internationalize.common.core.domain.SysUser;
+import com.ecell.internationalize.common.security.annotation.RequiresPermissions;
+import com.ecell.internationalize.common.security.annotation.RequiresRoles;
+
+/**
+ * @author borui
+ */
+
+public class AuthUtil {
+ /**
+ * 底层的 AuthLogic 对象
+ */
+ public static AuthLogic authLogic = new AuthLogic();
+
+ /**
+ * 会话注销
+ */
+ public static void logout()
+ {
+ authLogic.logout();
+ }
+
+ /**
+ * 会话注销,根据指定Token
+ *
+ * @param tokenValue 指定token
+ */
+ public static void logoutByToken(String token)
+ {
+ authLogic.logoutByToken(token);
+ }
+
+ /**
+ * 检验当前会话是否已经登录,如未登录,则抛出异常
+ */
+ public static void checkLogin()
+ {
+ authLogic.checkLogin();
+ }
+
+ /**
+ * 获取当前登录用户信息
+ */
+ public static LoginUser getLoginUser(String token)
+ {
+ return authLogic.getLoginUser(token);
+ }
+
+ /**
+ * 验证当前用户有效期
+ */
+ public static void verifyLoginUserExpire(LoginUser loginUser)
+ {
+ authLogic.verifyLoginUserExpire(loginUser);
+ }
+
+ /**
+ * 当前账号是否含有指定角色标识, 返回true或false
+ *
+ * @param role 角色标识
+ * @return 是否含有指定角色标识
+ */
+ public static boolean hasRole(String role)
+ {
+ return authLogic.hasRole(role);
+ }
+
+ /**
+ * 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
+ *
+ * @param role 角色标识
+ */
+ public static void checkRole(String role)
+ {
+ authLogic.checkRole(role);
+ }
+
+ /**
+ * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotRoleException
+ *
+ * @param requiresRoles 角色权限注解
+ */
+ public static void checkRole(RequiresRoles requiresRoles)
+ {
+ authLogic.checkRole(requiresRoles);
+ }
+
+ /**
+ * 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
+ *
+ * @param roles 角色标识数组
+ */
+ public static void checkRoleAnd(String... roles)
+ {
+ authLogic.checkRoleAnd(roles);
+ }
+
+ /**
+ * 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
+ *
+ * @param roles 角色标识数组
+ */
+ public static void checkRoleOr(String... roles)
+ {
+ authLogic.checkRoleOr(roles);
+ }
+
+ /**
+ * 当前账号是否含有指定权限, 返回true或false
+ *
+ * @param permission 权限码
+ * @return 是否含有指定权限
+ */
+ public static boolean hasPermi(String permission)
+ {
+ return authLogic.hasPermi(permission);
+ }
+
+ /**
+ * 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException
+ *
+ * @param permission 权限码
+ */
+ public static void checkPermi(String permission)
+ {
+ authLogic.checkPermi(permission);
+ }
+
+ /**
+ * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotPermissionException
+ *
+ * @param requiresPermissions 权限注解
+ */
+ public static void checkPermi(RequiresPermissions requiresPermissions)
+ {
+ authLogic.checkPermi(requiresPermissions);
+ }
+
+ /**
+ * 当前账号是否含有指定权限 [指定多个,必须全部验证通过]
+ *
+ * @param permissions 权限码数组
+ */
+ public static void checkPermiAnd(String... permissions)
+ {
+ authLogic.checkPermiAnd(permissions);
+ }
+
+ /**
+ * 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
+ *
+ * @param permissions 权限码数组
+ */
+ public static void checkPermiOr(String... permissions)
+ {
+ authLogic.checkPermiOr(permissions);
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/config/ApplicationConfig.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/config/ApplicationConfig.java
new file mode 100644
index 0000000..3491b5a
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/config/ApplicationConfig.java
@@ -0,0 +1,20 @@
+package com.ecell.internationalize.common.security.config;
+
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+
+import java.util.TimeZone;
+
+/**
+ * @author borui
+ */
+public class ApplicationConfig {
+ /**
+ * 时区配置
+ */
+ @Bean
+ public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
+ {
+ return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/config/WebMvcConfig.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/config/WebMvcConfig.java
new file mode 100644
index 0000000..925c9ac
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/config/WebMvcConfig.java
@@ -0,0 +1,30 @@
+package com.ecell.internationalize.common.security.config;
+
+import com.ecell.internationalize.common.security.interceptor.HeaderInterceptor;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author borui
+ */
+public class WebMvcConfig implements WebMvcConfigurer {
+ /** 不需要拦截地址 */
+ public static final String[] excludeUrls = { "/login", "/logout", "/refresh" };
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry)
+ {
+ registry.addInterceptor(getHeaderInterceptor())
+ .addPathPatterns("/**")
+ .excludePathPatterns(excludeUrls)
+ .order(-10);
+ }
+
+ /**
+ * 自定义请求头拦截器
+ */
+ public HeaderInterceptor getHeaderInterceptor()
+ {
+ return new HeaderInterceptor();
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/feign/FeignAutoConfiguration.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/feign/FeignAutoConfiguration.java
new file mode 100644
index 0000000..872ef46
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/feign/FeignAutoConfiguration.java
@@ -0,0 +1,17 @@
+package com.ecell.internationalize.common.security.feign;
+
+import feign.RequestInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author borui
+ */
+@Configuration
+public class FeignAutoConfiguration {
+ @Bean
+ public RequestInterceptor requestInterceptor()
+ {
+ return new FeignRequestInterceptor();
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/feign/FeignRequestInterceptor.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/feign/FeignRequestInterceptor.java
new file mode 100644
index 0000000..b3265be
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/feign/FeignRequestInterceptor.java
@@ -0,0 +1,48 @@
+package com.ecell.internationalize.common.security.feign;
+
+import com.ecell.internationalize.common.core.constant.SecurityConstants;
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import com.ecell.internationalize.common.core.utils.ip.IpUtils;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+/**
+ * @author borui
+ */
+@Component
+public class FeignRequestInterceptor implements RequestInterceptor {
+ @Override
+ public void apply(RequestTemplate requestTemplate)
+ {
+ HttpServletRequest httpServletRequest = ServletUtils.getRequest();
+ if (StringUtils.isNotNull(httpServletRequest))
+ {
+ Map headers = ServletUtils.getHeaders(httpServletRequest);
+ // 传递用户信息请求头,防止丢失
+ String userId = headers.get(SecurityConstants.DETAILS_USER_ID);
+ if (StringUtils.isNotEmpty(userId))
+ {
+ requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);
+ }
+ String userName = headers.get(SecurityConstants.DETAILS_USERNAME);
+ if (StringUtils.isNotEmpty(userName))
+ {
+ requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);
+ }
+ String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);
+ if (StringUtils.isNotEmpty(authentication))
+ {
+ requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);
+ }
+
+ // 配置客户端IP
+ requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr(ServletUtils.getRequest()));
+ }
+ }
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/handler/GlobalExceptionHandler.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..5aeb56c
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/handler/GlobalExceptionHandler.java
@@ -0,0 +1,125 @@
+package com.ecell.internationalize.common.security.handler;
+
+import com.ecell.internationalize.common.core.constant.HttpStatus;
+import com.ecell.internationalize.common.core.exception.InnerAuthException;
+import com.ecell.internationalize.common.core.exception.ServiceException;
+import com.ecell.internationalize.common.core.exception.auth.NotPermissionException;
+import com.ecell.internationalize.common.core.exception.auth.NotRoleException;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import com.ecell.internationalize.common.core.web.domain.AjaxResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author borui
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+ private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+ /**
+ * 权限码异常
+ */
+ @ExceptionHandler(NotPermissionException.class)
+ public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
+ return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
+ }
+
+ /**
+ * 角色权限异常
+ */
+ @ExceptionHandler(NotRoleException.class)
+ public AjaxResult handleNotRoleException(NotRoleException e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
+ return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
+ }
+
+ /**
+ * 请求方式不支持
+ */
+ @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+ public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+ HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 业务异常
+ */
+ @ExceptionHandler(ServiceException.class)
+ public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
+ {
+ log.error(e.getMessage(), e);
+ Integer code = e.getCode();
+ return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 拦截未知的运行时异常
+ */
+ @ExceptionHandler(RuntimeException.class)
+ public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',发生未知异常.", requestURI, e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 系统异常
+ */
+ @ExceptionHandler(Exception.class)
+ public AjaxResult handleException(Exception e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',发生系统异常.", requestURI, e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 自定义验证异常
+ */
+ @ExceptionHandler(BindException.class)
+ public AjaxResult handleBindException(BindException e)
+ {
+ log.error(e.getMessage(), e);
+ String message = e.getAllErrors().get(0).getDefaultMessage();
+ return AjaxResult.error(message);
+ }
+
+ /**
+ * 自定义验证异常
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
+ {
+ log.error(e.getMessage(), e);
+ String message = e.getBindingResult().getFieldError().getDefaultMessage();
+ return AjaxResult.error(message);
+ }
+
+ /**
+ * 内部认证异常
+ */
+ @ExceptionHandler(InnerAuthException.class)
+ public AjaxResult handleInnerAuthException(InnerAuthException e)
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/interceptor/HeaderInterceptor.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/interceptor/HeaderInterceptor.java
new file mode 100644
index 0000000..8508fff
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/interceptor/HeaderInterceptor.java
@@ -0,0 +1,52 @@
+package com.ecell.internationalize.common.security.interceptor;
+
+import com.ecell.internationalize.common.core.constant.SecurityConstants;
+import com.ecell.internationalize.common.core.context.SecurityContextHolder;
+import com.ecell.internationalize.common.core.domain.LoginUser;
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import com.ecell.internationalize.common.security.auth.AuthUtil;
+import com.ecell.internationalize.common.security.utils.SecurityUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.AsyncHandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author borui
+ */
+public class HeaderInterceptor implements AsyncHandlerInterceptor {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
+ {
+ if (!(handler instanceof HandlerMethod))
+ {
+ return true;
+ }
+
+ SecurityContextHolder.setUserId(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USER_ID));
+ SecurityContextHolder.setUserName(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USERNAME));
+ SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY));
+
+ String token = SecurityUtils.getToken();
+ if (StringUtils.isNotEmpty(token))
+ {
+ LoginUser loginUser = AuthUtil.getLoginUser(token);
+ if (StringUtils.isNotNull(loginUser))
+ {
+ AuthUtil.verifyLoginUserExpire(loginUser);
+ SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
+ throws Exception
+ {
+ SecurityContextHolder.remove();
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/service/TokenService.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/service/TokenService.java
new file mode 100644
index 0000000..5099663
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/service/TokenService.java
@@ -0,0 +1,170 @@
+package com.ecell.internationalize.common.security.service;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ecell.internationalize.common.core.constant.CacheConstants;
+import com.ecell.internationalize.common.core.constant.SecurityConstants;
+import com.ecell.internationalize.common.core.domain.LoginUser;
+import com.ecell.internationalize.common.core.domain.SysUser;
+import com.ecell.internationalize.common.core.utils.JwtUtils;
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import com.ecell.internationalize.common.core.utils.ip.IpUtils;
+import com.ecell.internationalize.common.core.utils.uuid.IdUtils;
+import com.ecell.internationalize.common.redis.service.RedisService;
+import com.ecell.internationalize.common.security.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author borui
+ */
+@Component
+public class TokenService {
+ @Autowired
+ private RedisService redisService;
+
+ protected static final long MILLIS_SECOND = 1000;
+
+ protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
+
+ private final static long expireTime = CacheConstants.EXPIRATION;
+
+ private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;
+
+ private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE;
+
+ /**
+ * 创建令牌
+ */
+ public Map createToken(LoginUser loginUser)
+ {
+ String token = IdUtils.fastUUID();
+ Long userId = loginUser.getSysUser().getUserId();
+ String userName = loginUser.getSysUser().getUserName();
+ loginUser.setToken(token);
+ loginUser.setUserid(userId);
+ loginUser.setUsername(userName);
+ loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
+ refreshToken(loginUser);
+
+ // Jwt存储信息
+ Map claimsMap = new HashMap();
+ claimsMap.put(SecurityConstants.USER_KEY, token);
+ claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
+ claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName);
+
+ // 接口返回信息
+ Map rspMap = new HashMap();
+ rspMap.put("access_token", JwtUtils.createToken(claimsMap));
+ rspMap.put("expires_in", expireTime);
+ return rspMap;
+ }
+
+ /**
+ * 获取用户身份信息
+ *
+ * @return 用户信息
+ */
+ public LoginUser getLoginUser()
+ {
+ return getLoginUser(ServletUtils.getRequest());
+ }
+
+ /**
+ * 获取用户身份信息
+ *
+ * @return 用户信息
+ */
+ public LoginUser getLoginUser(HttpServletRequest request)
+ {
+ // 获取请求携带的令牌
+ String token = SecurityUtils.getToken(request);
+ return getLoginUser(token);
+ }
+
+ /**
+ * 获取用户身份信息
+ *
+ * @return 用户信息
+ */
+ public LoginUser getLoginUser(String token)
+ {
+ LoginUser user = null;
+ try
+ {
+ if (StringUtils.isNotEmpty(token))
+ {
+ String userkey = JwtUtils.getUserKey(token);
+ user = redisService.getCacheObject(getTokenKey(userkey));
+ return user;
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ return user;
+ }
+
+ /**
+ * 设置用户身份信息
+ */
+ public void setLoginUser(LoginUser loginUser)
+ {
+ if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
+ {
+ refreshToken(loginUser);
+ }
+ }
+
+ /**
+ * 删除用户缓存信息
+ */
+ public void delLoginUser(String token)
+ {
+ if (StringUtils.isNotEmpty(token))
+ {
+ String userkey = JwtUtils.getUserKey(token);
+ redisService.deleteObject(getTokenKey(userkey));
+ }
+ }
+
+ /**
+ * 验证令牌有效期,相差不足120分钟,自动刷新缓存
+ *
+ * @param loginUser
+ */
+ public void verifyToken(LoginUser loginUser)
+ {
+ long expireTime = loginUser.getExpireTime();
+ long currentTime = System.currentTimeMillis();
+ if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
+ {
+ refreshToken(loginUser);
+ }
+ }
+
+ /**
+ * 刷新令牌有效期
+ *
+ * @param loginUser 登录信息
+ */
+ public void refreshToken(LoginUser loginUser)
+ {
+ loginUser.setLoginTime(System.currentTimeMillis());
+ loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
+ // 根据uuid将loginUser缓存
+ String userKey = getTokenKey(loginUser.getToken());
+ redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
+ }
+
+ private String getTokenKey(String token)
+ {
+ return ACCESS_TOKEN + token;
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/utils/SecurityUtils.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/utils/SecurityUtils.java
new file mode 100644
index 0000000..78bbf34
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-security/src/main/java/com/ecell/internationalize/common/security/utils/SecurityUtils.java
@@ -0,0 +1,159 @@
+package com.ecell.internationalize.common.security.utils;
+
+import com.ecell.internationalize.common.core.constant.SecurityConstants;
+import com.ecell.internationalize.common.core.constant.TokenConstants;
+import com.ecell.internationalize.common.core.context.SecurityContextHolder;
+import com.ecell.internationalize.common.core.domain.LoginUser;
+import com.ecell.internationalize.common.core.domain.SysUser;
+import com.ecell.internationalize.common.core.utils.ServletUtils;
+import com.ecell.internationalize.common.core.utils.StringUtils;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author borui
+ */
+public class SecurityUtils {
+ /**
+ * 获取用户ID
+ */
+ public static Long getUserId()
+ {
+ return SecurityContextHolder.getUserId();
+ }
+
+ /**
+ * yisai获取用户ID
+ */
+ public static String getStringUserId()
+ {
+ return SecurityContextHolder.getStringUserId();
+ }
+
+
+ /**
+ * 获取用户名称
+ */
+ public static String getUsername()
+ {
+ return SecurityContextHolder.getUserName();
+ }
+
+ /**
+ * 获取用户key
+ */
+ public static String getUserKey()
+ {
+ return SecurityContextHolder.getUserKey();
+ }
+
+ /**
+ * 获取登录用户信息
+ */
+ public static LoginUser getLoginUser()
+ {
+ return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
+ }
+
+ /**
+ * 获取请求token
+ */
+ public static String getToken()
+ {
+ return getToken(ServletUtils.getRequest());
+ }
+
+ /**
+ * 根据request获取请求token
+ */
+ public static String getToken(HttpServletRequest request)
+ {
+ // 从header获取token标识
+ String token = request.getHeader(TokenConstants.AUTHENTICATION);
+ return replaceTokenPrefix(token);
+ }
+
+ /**
+ * 裁剪token前缀
+ */
+ public static String replaceTokenPrefix(String token)
+ {
+ // 如果前端设置了令牌前缀,则裁剪掉前缀
+ if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
+ {
+ token = token.replaceFirst(TokenConstants.PREFIX, "");
+ }
+ return token;
+ }
+
+ /**
+ * 是否为管理员
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public static boolean isAdmin(Long userId)
+ {
+ return userId != null && 1L == userId;
+ }
+
+
+ /**
+ * yisai是否为管理员
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public static boolean isAdminString(String userId)
+ {
+ return userId != null && "1".equals(userId);
+ }
+
+ /**
+ * yisai是否为厂商
+ *
+ * @param firmFlag
+ * @return 结果
+ */
+ public static boolean isFirm(String firmFlag)
+ {
+ return firmFlag != null && "1".equals(firmFlag);
+ }
+
+ /**
+ * yisai是否为代理商
+ * @param firmFlag
+ * @return 结果
+ */
+ public static boolean isAgent(String firmFlag)
+ {
+ return firmFlag != null && "2".equals(firmFlag);
+ }
+
+
+ /**
+ * 生成BCryptPasswordEncoder密码
+ *
+ * @param password 密码
+ * @return 加密字符串
+ */
+ public static String encryptPassword(String password)
+ {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.encode(password);
+ }
+
+ /**
+ * 判断密码是否相同
+ *
+ * @param rawPassword 真实密码
+ * @param encodedPassword 加密后字符
+ * @return 结果
+ */
+ public static boolean matchesPassword(String rawPassword, String encodedPassword)
+ {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.matches(rawPassword, encodedPassword);
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/pom.xml b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/pom.xml
index 6fd6023..4d297d6 100644
--- a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/pom.xml
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/pom.xml
@@ -17,4 +17,21 @@
8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger.fox.version}
+
+
+
+
\ No newline at end of file
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/annotation/EnableCustomSwagger2.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/annotation/EnableCustomSwagger2.java
new file mode 100644
index 0000000..e47424d
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/annotation/EnableCustomSwagger2.java
@@ -0,0 +1,18 @@
+package com.ecell.internationalize.common.swagger.annotation;
+
+import com.ecell.internationalize.common.swagger.config.SwaggerAutoConfiguration;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * @author borui
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import({ SwaggerAutoConfiguration.class })
+public @interface EnableCustomSwagger2 {
+
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerAutoConfiguration.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerAutoConfiguration.java
new file mode 100644
index 0000000..5f04253
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerAutoConfiguration.java
@@ -0,0 +1,128 @@
+package com.ecell.internationalize.common.swagger.config;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * @author borui
+ */
+
+@Configuration
+@EnableSwagger2
+@EnableAutoConfiguration
+@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
+public class SwaggerAutoConfiguration {
+ /**
+ * 默认的排除路径,排除Spring Boot默认的错误处理路径和端点
+ */
+ private static final List DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");
+
+ private static final String BASE_PATH = "/**";
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SwaggerProperties swaggerProperties()
+ {
+ return new SwaggerProperties();
+ }
+
+ @Bean
+ public Docket api(SwaggerProperties swaggerProperties)
+ {
+ // base-path处理
+ if (swaggerProperties.getBasePath().isEmpty())
+ {
+ swaggerProperties.getBasePath().add(BASE_PATH);
+ }
+ // noinspection unchecked
+ List> basePath = new ArrayList>();
+ swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
+
+ // exclude-path处理
+ if (swaggerProperties.getExcludePath().isEmpty())
+ {
+ swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
+ }
+
+ List> excludePath = new ArrayList<>();
+ swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
+
+ ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost())
+ .apiInfo(apiInfo(swaggerProperties)).select()
+ .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
+
+ swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));
+ swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));
+
+ return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/");
+ }
+
+ /**
+ * 安全模式,这里指定token通过Authorization头请求头传递
+ */
+ private List securitySchemes()
+ {
+ List apiKeyList = new ArrayList();
+ apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
+ return apiKeyList;
+ }
+
+ /**
+ * 安全上下文
+ */
+ private List securityContexts()
+ {
+ List securityContexts = new ArrayList<>();
+ securityContexts.add(
+ SecurityContext.builder()
+ .securityReferences(defaultAuth())
+ .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
+ .build());
+ return securityContexts;
+ }
+
+ /**
+ * 默认的全局鉴权策略
+ *
+ * @return
+ */
+ private List defaultAuth()
+ {
+ AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+ AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+ authorizationScopes[0] = authorizationScope;
+ List securityReferences = new ArrayList<>();
+ securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+ return securityReferences;
+ }
+
+ private ApiInfo apiInfo(SwaggerProperties swaggerProperties)
+ {
+ return new ApiInfoBuilder()
+ .title(swaggerProperties.getTitle())
+ .description(swaggerProperties.getDescription())
+ .license(swaggerProperties.getLicense())
+ .licenseUrl(swaggerProperties.getLicenseUrl())
+ .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
+ .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
+ .version(swaggerProperties.getVersion())
+ .build();
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerBeanPostProcessor.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerBeanPostProcessor.java
new file mode 100644
index 0000000..472ca49
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerBeanPostProcessor.java
@@ -0,0 +1,45 @@
+package com.ecell.internationalize.common.swagger.config;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
+import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
+import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author borui
+ */
+@Component
+public class SwaggerBeanPostProcessor implements BeanPostProcessor {
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
+ customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
+ }
+ return bean;
+ }
+
+ private void customizeSpringfoxHandlerMappings(List mappings) {
+ List copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
+ .collect(Collectors.toList());
+ mappings.clear();
+ mappings.addAll(copy);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getHandlerMappings(Object bean) {
+ try {
+ Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
+ field.setAccessible(true);
+ return (List) field.get(bean);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerProperties.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerProperties.java
new file mode 100644
index 0000000..280fddf
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerProperties.java
@@ -0,0 +1,301 @@
+package com.ecell.internationalize.common.swagger.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author borui
+ */
+@Component
+@ConfigurationProperties("swagger")
+public class SwaggerProperties {
+ /**
+ * 是否开启swagger
+ */
+ private Boolean enabled;
+
+ /**
+ * swagger会解析的包路径
+ **/
+ private String basePackage = "";
+
+ /**
+ * swagger会解析的url规则
+ **/
+ private List basePath = new ArrayList<>();
+
+ /**
+ * 在basePath基础上需要排除的url规则
+ **/
+ private List excludePath = new ArrayList<>();
+
+ /**
+ * 标题
+ **/
+ private String title = "";
+
+ /**
+ * 描述
+ **/
+ private String description = "";
+
+ /**
+ * 版本
+ **/
+ private String version = "";
+
+ /**
+ * 许可证
+ **/
+ private String license = "";
+
+ /**
+ * 许可证URL
+ **/
+ private String licenseUrl = "";
+
+ /**
+ * 服务条款URL
+ **/
+ private String termsOfServiceUrl = "";
+
+ /**
+ * host信息
+ **/
+ private String host = "";
+
+ /**
+ * 联系人信息
+ */
+ private Contact contact = new Contact();
+
+ /**
+ * 全局统一鉴权配置
+ **/
+ private Authorization authorization = new Authorization();
+
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getBasePackage() {
+ return basePackage;
+ }
+
+ public void setBasePackage(String basePackage) {
+ this.basePackage = basePackage;
+ }
+
+ public List getBasePath() {
+ return basePath;
+ }
+
+ public void setBasePath(List basePath) {
+ this.basePath = basePath;
+ }
+
+ public List getExcludePath() {
+ return excludePath;
+ }
+
+ public void setExcludePath(List excludePath) {
+ this.excludePath = excludePath;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getLicense() {
+ return license;
+ }
+
+ public void setLicense(String license) {
+ this.license = license;
+ }
+
+ public String getLicenseUrl() {
+ return licenseUrl;
+ }
+
+ public void setLicenseUrl(String licenseUrl) {
+ this.licenseUrl = licenseUrl;
+ }
+
+ public String getTermsOfServiceUrl() {
+ return termsOfServiceUrl;
+ }
+
+ public void setTermsOfServiceUrl(String termsOfServiceUrl) {
+ this.termsOfServiceUrl = termsOfServiceUrl;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public Contact getContact() {
+ return contact;
+ }
+
+ public void setContact(Contact contact) {
+ this.contact = contact;
+ }
+
+ public Authorization getAuthorization() {
+ return authorization;
+ }
+
+ public void setAuthorization(Authorization authorization) {
+ this.authorization = authorization;
+ }
+
+ public static class Contact {
+ /**
+ * 联系人
+ **/
+ private String name = "";
+ /**
+ * 联系人url
+ **/
+ private String url = "";
+ /**
+ * 联系人email
+ **/
+ private String email = "";
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+ }
+
+ public static class Authorization {
+ /**
+ * 鉴权策略ID,需要和SecurityReferences ID保持一致
+ */
+ private String name = "";
+
+ /**
+ * 需要开启鉴权URL的正则
+ */
+ private String authRegex = "^.*$";
+
+ /**
+ * 鉴权作用域列表
+ */
+ private List authorizationScopeList = new ArrayList<>();
+
+ private List tokenUrlList = new ArrayList<>();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAuthRegex() {
+ return authRegex;
+ }
+
+ public void setAuthRegex(String authRegex) {
+ this.authRegex = authRegex;
+ }
+
+ public List getAuthorizationScopeList() {
+ return authorizationScopeList;
+ }
+
+ public void setAuthorizationScopeList(List authorizationScopeList) {
+ this.authorizationScopeList = authorizationScopeList;
+ }
+
+ public List getTokenUrlList() {
+ return tokenUrlList;
+ }
+
+ public void setTokenUrlList(List tokenUrlList) {
+ this.tokenUrlList = tokenUrlList;
+ }
+ }
+
+ public static class AuthorizationScope {
+ /**
+ * 作用域名称
+ */
+ private String scope = "";
+
+ /**
+ * 作用域描述
+ */
+ private String description = "";
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+ }
+}
diff --git a/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerWebConfiguration.java b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerWebConfiguration.java
new file mode 100644
index 0000000..d9f98cd
--- /dev/null
+++ b/ecell-internationalize/ecell-internationalize-common/ecell-internationalize-swagger/src/main/java/com/ecell/internationalize/common/swagger/config/SwaggerWebConfiguration.java
@@ -0,0 +1,20 @@
+package com.ecell.internationalize.common.swagger.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author borui
+ */
+@Configuration
+public class SwaggerWebConfiguration implements WebMvcConfigurer {
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry)
+ {
+ /** swagger-ui 地址 */
+ registry.addResourceHandler("/swagger-ui/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
+ }
+
+}
diff --git a/ecell-internationalize/pom.xml b/ecell-internationalize/pom.xml
index fda20e7..3b9f949 100644
--- a/ecell-internationalize/pom.xml
+++ b/ecell-internationalize/pom.xml
@@ -12,6 +12,7 @@
ecell-internationalize-app
ecell-internationalize-common
ecell-internationalize-gateway
+ ecell-internationalize-auth