feat(login): 新增网页AI登录场景WEB_AI
- 在LoginSceneEnum中增加WEB_AI枚举,绑定路径webAi-doLogin
- LoginService扩展WEB_AI登录逻辑:缓存登录态、创建w.tenant.{tenantId}队列并绑定webAiHeadersExchange
- 新增webAiHeadersExchange Bean,交换机名web.ai.headers.exchange
- 用户实体与Service增加web_ai字段及checkWebAILoginRole权限校验
- 提供/webAi-doLogin接口,支持网页端AI独立登录与Token管理
This commit is contained in:
@@ -23,6 +23,7 @@ public class RabbitMQConfig {
|
|||||||
public static final String EXCHANGE_NAME = "user.headers.exchange";
|
public static final String EXCHANGE_NAME = "user.headers.exchange";
|
||||||
public static final String AI_CHAT_EXCHANGE_NAME = "ai.chat.headers.exchange";
|
public static final String AI_CHAT_EXCHANGE_NAME = "ai.chat.headers.exchange";
|
||||||
public static final String BIG_BROTHER_EXCHANGE_NAME = "big.brother.headers.exchange";
|
public static final String BIG_BROTHER_EXCHANGE_NAME = "big.brother.headers.exchange";
|
||||||
|
public static final String WEB_AI_EXCHANGE_NAME = "web.ai.headers.exchange";
|
||||||
|
|
||||||
//创建队列
|
//创建队列
|
||||||
//true:表示持久化
|
//true:表示持久化
|
||||||
@@ -55,12 +56,20 @@ public class RabbitMQConfig {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public HeadersExchange bigBrotherHeadersExchange() {
|
public HeadersExchange bigBrotherHeadersExchange() {
|
||||||
return ExchangeBuilder.headersExchange(BIG_BROTHER_EXCHANGE_NAME)
|
return ExchangeBuilder.headersExchange(BIG_BROTHER_EXCHANGE_NAME)
|
||||||
.durable(true)
|
.durable(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
/** 网页AI使用的 HeadersExchange */
|
||||||
|
@Bean
|
||||||
|
public HeadersExchange webAiHeadersExchange() {
|
||||||
|
return ExchangeBuilder.headersExchange(WEB_AI_EXCHANGE_NAME)
|
||||||
|
.durable(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RabbitAdmin rabbitAdmin(ConnectionFactory cf) {
|
public RabbitAdmin rabbitAdmin(ConnectionFactory cf) {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
|||||||
"/user/bigbrother-doLogin",
|
"/user/bigbrother-doLogin",
|
||||||
"/user/aiChat-doLogin",
|
"/user/aiChat-doLogin",
|
||||||
"/user/aiChat-logout",
|
"/user/aiChat-logout",
|
||||||
|
"/user/webAi-doLogin",
|
||||||
"/error",
|
"/error",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ public class UserController {
|
|||||||
return ResultUtils.success(loginService.aiChatLogout(usersDTO));
|
return ResultUtils.success(loginService.aiChatLogout(usersDTO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("webAi-doLogin")
|
||||||
|
public BaseResponse<SystemUsersVO> webAiDoLogin(@RequestBody SystemUsersDTO usersDTO) {
|
||||||
|
return ResultUtils.success(loginService.login(LoginSceneEnum.WEB_AI, usersDTO));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/logout")
|
@GetMapping("/logout")
|
||||||
public BaseResponse<Boolean> logout(){
|
public BaseResponse<Boolean> logout(){
|
||||||
return ResultUtils.success(loginService.logout());
|
return ResultUtils.success(loginService.logout());
|
||||||
|
|||||||
@@ -188,4 +188,11 @@ public class SystemUsers {
|
|||||||
@TableField(value = "ai_replay")
|
@TableField(value = "ai_replay")
|
||||||
@ApiModelProperty(value = "是否开启智能回复")
|
@ApiModelProperty(value = "是否开启智能回复")
|
||||||
private Byte aiReplay;
|
private Byte aiReplay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 能否登录智能回复客户端
|
||||||
|
*/
|
||||||
|
@TableField(value = "web_ai")
|
||||||
|
@ApiModelProperty(value = "能否登录智能回复客户端")
|
||||||
|
private Byte webAi;
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,8 @@ import lombok.Getter;
|
|||||||
public enum LoginSceneEnum {
|
public enum LoginSceneEnum {
|
||||||
HOST("doLogin", "host", "checkCrawlRole"),
|
HOST("doLogin", "host", "checkCrawlRole"),
|
||||||
BIG_BROTHER("bigbrother-doLogin", "bigbrother", "checkBigBrotherRole"),
|
BIG_BROTHER("bigbrother-doLogin", "bigbrother", "checkBigBrotherRole"),
|
||||||
AI_CHAT("aiChat-doLogin", "aiChat", "checkAiChatLoginRole");
|
AI_CHAT("aiChat-doLogin", "aiChat", "checkAiChatLoginRole"),
|
||||||
|
WEB_AI("webAiChat-doLogin", "webAiChat", "checkWebAiChatLoginRole");
|
||||||
|
|
||||||
private final String path; // 对应 @PostMapping
|
private final String path; // 对应 @PostMapping
|
||||||
private final String saMode; // Sa-Token 登录模式
|
private final String saMode; // Sa-Token 登录模式
|
||||||
|
|||||||
@@ -24,4 +24,6 @@ public interface SystemUsersService extends IService<SystemUsers> {
|
|||||||
boolean checkbigBrotherlRole(Long userId);
|
boolean checkbigBrotherlRole(Long userId);
|
||||||
|
|
||||||
boolean checkAiCHatLoginRole(Long userId);
|
boolean checkAiCHatLoginRole(Long userId);
|
||||||
|
|
||||||
|
boolean checkWebAILoginRole(Long userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ public class LoginService {
|
|||||||
/** 大哥使用的 HeadersExchange */
|
/** 大哥使用的 HeadersExchange */
|
||||||
private final HeadersExchange bigBrotherHeadersExchange;
|
private final HeadersExchange bigBrotherHeadersExchange;
|
||||||
|
|
||||||
|
/** 网页AI使用的 HeadersExchange */
|
||||||
|
private final HeadersExchange webAiHeadersExchange;
|
||||||
|
|
||||||
/** RabbitMQ 管理组件 */
|
/** RabbitMQ 管理组件 */
|
||||||
@Resource
|
@Resource
|
||||||
private RabbitAdmin rabbitAdmin;
|
private RabbitAdmin rabbitAdmin;
|
||||||
@@ -108,6 +111,20 @@ public class LoginService {
|
|||||||
.match();
|
.match();
|
||||||
rabbitAdmin.declareBinding(binding);
|
rabbitAdmin.declareBinding(binding);
|
||||||
}
|
}
|
||||||
|
if (scene.equals(LoginSceneEnum.WEB_AI)) {
|
||||||
|
redisTemplate.opsForValue().set("webAI_login:" + user.getTenantId() + ":" + user.getId(), true);
|
||||||
|
String queueName = "w.tenant." + user.getTenantId();
|
||||||
|
// 若该租户队列尚未创建,则创建队列并绑定到 HeadersExchange
|
||||||
|
Queue queue = QueueBuilder.durable(queueName).build();
|
||||||
|
rabbitAdmin.declareQueue(queue);
|
||||||
|
Map<String, Object> headers = Map.of("tenantId", user.getTenantId(), "x-match", "all");
|
||||||
|
Binding binding = BindingBuilder
|
||||||
|
.bind(queue)
|
||||||
|
.to(webAiHeadersExchange) // 使用webAi专用交换机
|
||||||
|
.whereAll(headers)
|
||||||
|
.match();
|
||||||
|
rabbitAdmin.declareBinding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
SystemTenant systemTenant = tenantMapper.selectById(user.getTenantId());
|
SystemTenant systemTenant = tenantMapper.selectById(user.getTenantId());
|
||||||
// 封装返回数据
|
// 封装返回数据
|
||||||
@@ -120,6 +137,7 @@ public class LoginService {
|
|||||||
StpUtil.login(user.getId(), scene.getSaMode());
|
StpUtil.login(user.getId(), scene.getSaMode());
|
||||||
switch (scene) {
|
switch (scene) {
|
||||||
case AI_CHAT:
|
case AI_CHAT:
|
||||||
|
StpUtil.logout(user.getId(), LoginSceneEnum.WEB_AI.getSaMode());
|
||||||
StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(),DateUtil.date()));
|
StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(),DateUtil.date()));
|
||||||
BeanUtil.copyProperties(user, vo);
|
BeanUtil.copyProperties(user, vo);
|
||||||
vo.setTokenName(StpUtil.getTokenName());
|
vo.setTokenName(StpUtil.getTokenName());
|
||||||
@@ -140,6 +158,14 @@ public class LoginService {
|
|||||||
vo.setTokenValue(StpUtil.getTokenValue());
|
vo.setTokenValue(StpUtil.getTokenValue());
|
||||||
vo.setBrotherExpireTime(systemTenant.getBrotherExpireTime());
|
vo.setBrotherExpireTime(systemTenant.getBrotherExpireTime());
|
||||||
return vo;
|
return vo;
|
||||||
|
case WEB_AI:
|
||||||
|
StpUtil.logout(user.getId(), LoginSceneEnum.AI_CHAT.getSaMode());
|
||||||
|
StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(),DateUtil.date()));
|
||||||
|
BeanUtil.copyProperties(user, vo);
|
||||||
|
vo.setTokenName(StpUtil.getTokenName());
|
||||||
|
vo.setTokenValue(StpUtil.getTokenValue());
|
||||||
|
vo.setAiExpireTime(systemTenant.getAiExpireTime());
|
||||||
|
return vo;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -180,6 +206,7 @@ public class LoginService {
|
|||||||
case HOST -> usersService.checkCrawlRole(userId);
|
case HOST -> usersService.checkCrawlRole(userId);
|
||||||
case BIG_BROTHER -> usersService.checkbigBrotherlRole(userId);
|
case BIG_BROTHER -> usersService.checkbigBrotherlRole(userId);
|
||||||
case AI_CHAT -> usersService.checkAiCHatLoginRole(userId);
|
case AI_CHAT -> usersService.checkAiCHatLoginRole(userId);
|
||||||
|
case WEB_AI -> usersService.checkWebAILoginRole(userId);
|
||||||
};
|
};
|
||||||
if (!pass) {
|
if (!pass) {
|
||||||
throw new BusinessException(ErrorCode.LOGIN_NOT_ALLOWED);
|
throw new BusinessException(ErrorCode.LOGIN_NOT_ALLOWED);
|
||||||
@@ -194,19 +221,28 @@ public class LoginService {
|
|||||||
*/
|
*/
|
||||||
public Boolean aiChatLogout(SystemUsersDTO usersDTO) {
|
public Boolean aiChatLogout(SystemUsersDTO usersDTO) {
|
||||||
// 1. 删除 Redis 中该用户的 AI_CHAT 登录标记
|
// 1. 删除 Redis 中该用户的 AI_CHAT 登录标记
|
||||||
Boolean delete = redisTemplate.delete("ai_login:" + usersDTO.getTenantId() + ":" + usersDTO.getUserId());
|
Boolean ai_login = redisTemplate.delete("ai_login:" + usersDTO.getTenantId() + ":" + usersDTO.getUserId());
|
||||||
|
Boolean webAi_login = redisTemplate.delete("webAI_login:" + usersDTO.getTenantId() + ":" + usersDTO.getUserId());
|
||||||
|
|
||||||
|
|
||||||
// 2. 使当前 Token 失效
|
// 2. 使当前 Token 失效
|
||||||
String tokenValue = StpUtil.getTokenValue();
|
String tokenValue = StpUtil.getTokenValue();
|
||||||
StpUtil.logoutByTokenValue(tokenValue);
|
StpUtil.logoutByTokenValue(tokenValue);
|
||||||
|
|
||||||
log.info("删除租户:{} 登录状态:{}", usersDTO.getTenantId(), delete);
|
log.info("删除租户:{} 登录状态:{}", usersDTO.getTenantId(), ai_login);
|
||||||
|
log.info("删除租户:{} 登录状态:{}", usersDTO.getTenantId(), webAi_login);
|
||||||
|
|
||||||
// 3. 若该租户下已无 AI_CHAT 在线用户,则删除队列
|
// 3. 若该租户下已无 AI_CHAT 在线用户,则删除队列
|
||||||
if (!redisUtils.hasKeyByPrefix("ai_login:" + usersDTO.getTenantId())) {
|
if (!redisUtils.hasKeyByPrefix("ai_login:" + usersDTO.getTenantId())) {
|
||||||
boolean b = rabbitAdmin.deleteQueue("q.tenant." + usersDTO.getTenantId());
|
boolean b = rabbitAdmin.deleteQueue("q.tenant." + usersDTO.getTenantId());
|
||||||
log.info("删除租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b);
|
log.info("删除Ai_CHAT租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!redisUtils.hasKeyByPrefix("webAI_login:" + usersDTO.getTenantId())) {
|
||||||
|
boolean b = rabbitAdmin.deleteQueue("w.tenant." + usersDTO.getTenantId());
|
||||||
|
log.info("删除Web_AI租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,5 +83,12 @@ public class SystemUsersServiceImpl extends ServiceImpl<SystemUsersMapper,System
|
|||||||
return systemUsers.getAiChat() == 1;
|
return systemUsers.getAiChat() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkWebAILoginRole(Long userId) {
|
||||||
|
SystemUsers systemUsers = baseMapper.selectById(userId);
|
||||||
|
return systemUsers.getWebAi() == 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user