# 常见问题
# 如何不登录直接访问
登录nacos
在配置管理
中配置列表
,修改ruoyi-gateway-dev.yml
在ignore
中设置whites
,表示允许匿名访问
# 不校验白名单
security:
ignore:
whites:
- /auth/logout
- /auth/login
- /*/v2/api-docs
- /csrf
2
3
4
5
6
7
8
# 如何获取用户登录信息
后端获取当前用户信息
// 获取当前用户名
String username = SecurityUtils.getUsername();
// 获取当前用户ID
Long userid = SecurityUtils.getUserId();
// 获取当前的用户信息
LoginUser loginUser = SecurityUtils.getLoginUser();
2
3
4
5
6
7
8
vue中获取当前用户信息
// 获取当前用户名
var username = this.$store.state.user.name;
2
# 如何更换项目包路径
可以使用若依框架包名修改器 (opens new window)一键替换。
# 如何设置令牌有效期
可以在ruoyi-common-core
模块中的com.ruoyi.common.core.constant.CacheConstants
类中设置。
/**
* 缓存有效期,默认720(分钟)
*/
public final static long EXPIRATION = 720;
/**
* 缓存刷新时间,默认120(分钟)
*/
public final static long REFRESH_TIME = 120;
2
3
4
5
6
7
8
9
# 提示您没有数据的权限
这种情况都属于权限标识配置不对在菜单管理
配置好权限标识(菜单&按钮)
- 确认此用户是否已经配置角色
- 确认此角色是否已经配置菜单权限
- 确认此菜单权限标识是否和后台代码一致
如参数管理
后台配置@RequiresPermissions("system:config:list")
对应参数管理权限标识为system:config:list
注:如需要角色权限,配置角色权限字符 使用@RequiresRoles("admin")
# Swagger的启用和禁用
通过nacos
找到自己业务模块,如ruoyi-system-dev.yml
,配置swagger.enabled
控制。为true
时表示启用,为false
时表示禁用。
记得关闭
为了系统安全,通常生产环境不建议开启swagger。
# 系统接口不显示对应服务
访问swagger
右上角服务列表没有展示新增服务,确认是否在ruoyi-gateway-dev.yml
配置了对应服务的路由。
配置示例
spring:
cloud:
gateway:
routes:
# xxxx服务
- id: ruoyi-xxxx
uri: lb://ruoyi-xxxx
predicates:
- Path=/xxxx/**
filters:
- StripPrefix=1
2
3
4
5
6
7
8
9
10
11
因为swagger
右上角服务列表默认是读取的gateway
中的routes
服务列表。
# 登录页面如何不显示验证码
登录nacos
在配置管理
中配置列表
,修改ruoyi-gateway-dev.yml
在captcha
中设置enabled
属性(true
开启、false
关闭)
# 验证码
security:
captcha:
enabled: false
2
3
4
# 登录密码如何使用加密传输
目前登录接口密码是明文传输,如果安全性有要求,可以调整成加密方式传输。参考如下
1、修改前端login.js
对密码进行rsa
加密。
import { encrypt } from '@/utils/jsencrypt'
export function login(username, password, code, uuid) {
password = encrypt(password);
.........
}
2
3
4
5
6
2、工具类sign
包下添加RsaUtils.java
,用于RSA
加密解密。
package com.ruoyi.common.core.utils.sign;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* RSA加密解密
*
* @author ruoyi
**/
public class RsaUtils
{
// Rsa 私钥
public static String privateKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY"
+ "7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN"
+ "PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA"
+ "kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow"
+ "cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv"
+ "DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh"
+ "YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3"
+ "UP8iWi1Qw0Y=";
/**
* 私钥解密
*
* @param privateKeyString 私钥
* @param text 待解密的文本
* @return 解密后的文本
*/
public static String decryptByPrivateKey(String text) throws Exception
{
return decryptByPrivateKey(privateKey, text);
}
/**
* 公钥解密
*
* @param publicKeyString 公钥
* @param text 待解密的信息
* @return 解密后的文本
*/
public static String decryptByPublicKey(String publicKeyString, String text) throws Exception
{
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 私钥加密
*
* @param privateKeyString 私钥
* @param text 待加密的信息
* @return 加密后的文本
*/
public static String encryptByPrivateKey(String privateKeyString, String text) throws Exception
{
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 私钥解密
*
* @param privateKeyString 私钥
* @param text 待解密的文本
* @return 解密后的文本
*/
public static String decryptByPrivateKey(String privateKeyString, String text) throws Exception
{
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 公钥加密
*
* @param publicKeyString 公钥
* @param text 待加密的文本
* @return 加密后的文本
*/
public static String encryptByPublicKey(String publicKeyString, String text) throws Exception
{
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 构建RSA密钥对
*
* @return 生成后的公私钥信息
*/
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException
{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
return new RsaKeyPair(publicKeyString, privateKeyString);
}
/**
* RSA密钥对对象
*/
public static class RsaKeyPair
{
private final String publicKey;
private final String privateKey;
public RsaKeyPair(String publicKey, String privateKey)
{
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public String getPublicKey()
{
return publicKey;
}
public String getPrivateKey()
{
return privateKey;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
3、登录方法TokenController.java
,对密码进行rsa
解密。
@PostMapping("login")
public R<?> login(@RequestBody LoginBody form) throws Exception
{
// 用户登录
LoginUser userInfo = sysLoginService.login(form.getUsername(), RsaUtils.decryptByPrivateKey(form.getPassword()));
// 获取登录token
return R.ok(tokenService.createToken(userInfo));
}
2
3
4
5
6
7
8
访问 http://localhost/login (opens new window) 登录页面。提交时检查密码是否为加密传输,且后台也能正常解密。
# 特殊字符串被过滤的解决办法
默认所有的都会过滤脚本,可以在ruoyi-gateway-dev.yml
配置xss.excludeUrls
属性排除URL
# 安全配置
security:
xss:
enabled: true
excludeUrls:
- /system/notice
2
3
4
5
6
# 如何区分不同环境下配置文件
当在多配置文件中,需要切换配置文件时,通常的做法都是修改激活的文件名称,而spring.profiles.active=@profiles.active@
是配合maven profile
进行选择不同配置文件进行启动,可以避免修改文件,而在maven
打包是指定使用哪个配置文件。
1、配置pom.xml
,定义不同环境配置属性。
<profiles>
<profile>
<!-- 本地环境 -->
<id>dev</id>
<properties>
<spring.profile>dev</spring.profile>
<nacos.server.address>127.0.0.1:8848</nacos.server.address>
</properties>
<activation>
<!-- 是否默认激活 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 测试环境 -->
<id>test</id>
<properties>
<spring.profile>test</spring.profile>
<nacos.server.address>120.120.120.120:8848</nacos.server.address>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<!-- 生产环境 -->
<id>prod</id>
<properties>
<spring.profile>prod</spring.profile>
<nacos.server.address>http://ruoyi.vip:8848</nacos.server.address>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
</profiles>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2、修改对应的配置文件,示例如下。
# Tomcat
server:
port: 9201
# Spring
spring:
application:
# 应用名称
name: ruoyi-system
profiles:
# 环境配置
active: @spring.profile@
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: @nacos.server.address@
config:
# 配置中心地址
server-addr: @nacos.server.address@
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3、打包测试。
mvn clean package -P dev
mvn clean package -P test
mvn clean package -P prod
2
3
打包成功后会进行对应的替换,例如使用test
环境打包,配置文件的@nacos.server.address@
会被替换成pom.xml
测试配置环境变量nacos.server.address
值120.120.120.120:8848
。
# 如何处理Long类型精度丢失问题
当字段实体类为Long
类型且值超过前端js
显示的长度范围时会导致前端回显错误,解决方案如下
1、ruoyi-common-security
模块添加JacksonConfig
配置全局序列化
package com.ruoyi.common.security.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
/**
* Jackson配置
*
* @author ruoyi
*/
@Configuration
public class JacksonConfig {
@SuppressWarnings("deprecation")
@Bean
public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
final ObjectMapper objectMapper = builder.build();
SimpleModule simpleModule = new SimpleModule();
// Long 转为 String 防止 js 丢失精度
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
// 忽略 transient 关键词属性
objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
return new MappingJackson2HttpMessageConverter(objectMapper);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2、在resources\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件中新增com.ruoyi.common.security.config.JacksonConfig
自动配置类
com.ruoyi.common.security.config.WebMvcConfig
com.ruoyi.common.security.config.JacksonConfig
com.ruoyi.common.security.service.TokenService
com.ruoyi.common.security.aspect.PreAuthorizeAspect
com.ruoyi.common.security.aspect.InnerAuthAspect
com.ruoyi.common.security.handler.GlobalExceptionHandler
2
3
4
5
6
# Druid更多项目常见问题
Druid更多项目常见问题点我进入 (opens new window)
# Nacos更多项目常见问题
Nacos更多项目常见问题点我进入 (opens new window)
# Seata更多项目常见问题
Seata更多项目常见问题点我进入 (opens new window)
# Sentinel更多项目常见问题
Sentinel更多项目常见问题点我进入 (opens new window)
# RuoYi更多项目常见问题查询
微服务版本问题和不分离版本大多数雷同。
# RuoYi-Vue更多项目常见问题查询
微服务版本问题和分离版本大多数雷同。