feat(auth): 添加CAS单点登录功能

- 配置开发和生产环境的CAS登录URL和登出URL
- 新增CacheHelper缓存工具类用于缓存操作
- 创建LideeUserDto用户数据传输对象
- 在SecurityConfig中允许CAS登录和登出接口匿名访问
- 添加SysLoginController中的logincas和outlogcas接口
- 实现SysLoginService中的CAS登录验证和登出逻辑
- 集成HttpUtils进行CAS服务器通信验证

Signed-off-by: NewName <1048783178@qq.com>
This commit is contained in:
NewName
2026-03-27 16:18:58 +08:00
parent 4dbe762e2c
commit 71a3807825
7 changed files with 208 additions and 2 deletions

View File

@@ -1,14 +1,17 @@
package iot.lidee.web.controller.system; package iot.lidee.web.controller.system;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import iot.lidee.common.core.domain.model.LideeUserDto;
import iot.lidee.system.domain.AppPreferences; import iot.lidee.system.domain.AppPreferences;
import iot.lidee.system.service.IAppPreferencesService; import iot.lidee.system.service.IAppPreferencesService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -69,6 +72,29 @@ public class SysLoginController
return ajax; return ajax;
} }
/**
* 登录方法
*
* @return 结果
*/
@PostMapping({"/logincas"})
public AjaxResult logincas(@RequestBody @Validated LideeUserDto dto) {
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.logincas(dto);
ajax.put(Constants.TOKEN, token);
return ajax;
}
@PostMapping({"/outlogcas"})
public AjaxResult outlogcas(@RequestBody @Validated LideeUserDto dto){
// 生成令牌
loginService.outlogcas(dto);
return AjaxResult.success();
}
/** /**
* 获取用户信息 * 获取用户信息
* *

View File

@@ -147,4 +147,9 @@ logging:
swagger: swagger:
enabled: true # 是否开启swagger enabled: true # 是否开启swagger
pathMapping: /dev-api # 请求前缀 pathMapping: /dev-api # 请求前缀
cas:
loginurl: http://127.0.0.1:48080/admin-api/system/auth/user-info
outlogouturl: http://127.0.0.1:48080/admin-api/system/auth/logout-client
# loginurl: http://192.168.1.241/admin-api/system/auth/user-info
# outlogouturl: http://192.168.1.241/admin-api/system/auth/logout-client

View File

@@ -147,4 +147,9 @@ logging:
swagger: swagger:
enabled: true # 是否开启swagger enabled: true # 是否开启swagger
pathMapping: /dev-api # 请求前缀 pathMapping: /dev-api # 请求前缀
cas:
# loginurl: http://127.0.0.1:48080/admin-api/system/auth/user-info
# outlogouturl: http://127.0.0.1:48080/admin-api/system/auth/logout-client
loginurl: http://192.168.1.241/admin-api/system/auth/user-info
outlogouturl: http://192.168.1.241/admin-api/system/auth/logout-client

View File

@@ -0,0 +1,50 @@
package iot.lidee.common.core.cache;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Component
public class CacheHelper {
/**
* 获取指定key的String类型缓存
* @param key
* @return
*/
public String stringGet(String key) {
return null;
}
Map<String,String> stringMultiGet(List<String> keys) {
return null;
}
/**
* 设置指定key的String类型缓存
* @param key
* @param value 缓存值
* @return
*/
public void stringSet(String key, String value) {
}
/**
* 设置指定key的String类型缓存包含过期时间
* @param key
* @param value
* @param seconds
*/
public void stringSetExpire(String key, String value, long seconds) {
}
/**
* 是否存在指定KEY
* @param key
* @return
*/
public boolean exist(String key) {
return false;
}
}

View File

@@ -0,0 +1,27 @@
package iot.lidee.common.core.domain.model;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.List;
@Data
public class LideeUserDto {
/** 登录名*/
@NotBlank
private String loginName;
/** 密码*/
@NotBlank
private String password;
/** 真实用户 */
private String realName;
/** 登录成功后的 */
private String token;
/** 用户所拥有的权限合集 */
private List<String> authorities;
}

View File

@@ -115,7 +115,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage","/iot/tool/register","/iot/tool/ntp", .antMatchers("/login", "/register", "/captchaImage","/iot/tool/register","/iot/tool/ntp",
"/iot/tool/mqtt/auth","/iot/tool/mqtt/authv5","/iot/tool/mqtt/webhook","/iot/tool/mqtt/webhookv5","/auth/**/**", "/iot/tool/mqtt/auth","/iot/tool/mqtt/authv5","/iot/tool/mqtt/webhook","/iot/tool/mqtt/webhookv5","/auth/**/**",
"/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll() "/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback","/logincas","/outlogcas").permitAll()
.antMatchers("/zlmhook/**").permitAll() .antMatchers("/zlmhook/**").permitAll()
//.antMatchers("/sip/player/getBigScreenUrl/**").permitAll() //.antMatchers("/sip/player/getBigScreenUrl/**").permitAll()
.antMatchers("/ruleengine/rulemanager/**").permitAll() .antMatchers("/ruleengine/rulemanager/**").permitAll()

View File

@@ -1,9 +1,13 @@
package iot.lidee.framework.web.service; package iot.lidee.framework.web.service;
import com.alibaba.fastjson2.JSONObject;
import iot.lidee.common.constant.CacheConstants; import iot.lidee.common.constant.CacheConstants;
import iot.lidee.common.constant.Constants; import iot.lidee.common.constant.Constants;
import iot.lidee.common.constant.LideeConstant;
import iot.lidee.common.core.cache.CacheHelper;
import iot.lidee.common.core.domain.entity.SysDept; import iot.lidee.common.core.domain.entity.SysDept;
import iot.lidee.common.core.domain.entity.SysUser; import iot.lidee.common.core.domain.entity.SysUser;
import iot.lidee.common.core.domain.model.LideeUserDto;
import iot.lidee.common.core.domain.model.LoginUser; import iot.lidee.common.core.domain.model.LoginUser;
import iot.lidee.common.core.redis.RedisCache; import iot.lidee.common.core.redis.RedisCache;
import iot.lidee.common.enums.UserStatus; import iot.lidee.common.enums.UserStatus;
@@ -15,6 +19,7 @@ import iot.lidee.common.utils.DateUtils;
import iot.lidee.common.utils.MessageUtils; import iot.lidee.common.utils.MessageUtils;
import iot.lidee.common.utils.ServletUtils; import iot.lidee.common.utils.ServletUtils;
import iot.lidee.common.utils.StringUtils; import iot.lidee.common.utils.StringUtils;
import iot.lidee.common.utils.http.HttpUtils;
import iot.lidee.common.utils.ip.IpUtils; import iot.lidee.common.utils.ip.IpUtils;
import iot.lidee.framework.manager.AsyncManager; import iot.lidee.framework.manager.AsyncManager;
import iot.lidee.framework.manager.factory.AsyncFactory; import iot.lidee.framework.manager.factory.AsyncFactory;
@@ -22,7 +27,9 @@ import iot.lidee.framework.security.context.AuthenticationContextHolder;
import iot.lidee.system.service.ISysConfigService; import iot.lidee.system.service.ISysConfigService;
import iot.lidee.system.service.ISysDeptService; import iot.lidee.system.service.ISysDeptService;
import iot.lidee.system.service.ISysUserService; import iot.lidee.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -37,6 +44,7 @@ import javax.annotation.Resource;
* *
* @author ruoyi * @author ruoyi
*/ */
@Slf4j
@Component @Component
public class SysLoginService { public class SysLoginService {
@Autowired @Autowired
@@ -62,6 +70,18 @@ public class SysLoginService {
@Resource @Resource
private ISysDeptService sysDeptService; private ISysDeptService sysDeptService;
@Resource
private SysPermissionService permissionService;
@Resource
private CacheHelper cacheHelper;
@Value("${cas.loginurl:}")
private String casLoginUrl;
@Value("${cas.outlogouturl:}")
private String casoutlogouturl;
/** /**
* 登录验证 * 登录验证
* *
@@ -262,4 +282,77 @@ public class SysLoginService {
// 生成token // 生成token
return tokenService.createToken(loginUser); return tokenService.createToken(loginUser);
} }
public String logincas(LideeUserDto dto) {
String loginName = validateCasToken(dto.getLoginName());
if (StringUtils.isNull(loginName)) {
throw new ServiceException("该用户不存在!");
}
SysUser accessUser = userService.selectUserByUserName(loginName);
if (null == accessUser) {
throw new ServiceException("该用户不存在!");
}
Long deptId = accessUser.getDeptId();
SysDept sysDept = null;
if (deptId != null) {
sysDept = sysDeptService.selectDeptById(deptId);
}
LoginUser loginUser = new LoginUser(
accessUser.getUserId(),
deptId,
null,
accessUser,
permissionService.getMenuPermission(accessUser)
);
if (sysDept != null) {
loginUser.setDeptUserId(sysDept.getDeptUserId());
}
redisCache.setCacheObject(loginName + "_cas", dto.getLoginName());
recordLoginInfo(loginUser.getUserId());
AsyncManager.me().execute(AsyncFactory.recordLogininfor(
accessUser.getUserName(),
Constants.LOGIN_SUCCESS,
MessageUtils.message("user.login.success")
));
return tokenService.createToken(loginUser);
}
private String validateCasToken(String refreshToken) {
String url = casLoginUrl + "?refreshToken=" + refreshToken;
String response = HttpUtils.sendPost(url, refreshToken);
if (StringUtils.isEmpty(response)) {
return "";
}
try {
JSONObject jsonObject = JSONObject.parseObject(response);
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
JSONObject data = jsonObject.getJSONObject("data");
if (data != null) {
return data.getString("username");
}
}
} catch (Exception e) {
SysLoginService.log.error("CAS 验证失败", e);
}
return "";
}
public void outlogcas(LideeUserDto dto) {
String token= redisCache.getCacheObject(dto.getLoginName()+"_cas");
String url = casoutlogouturl+"?refreshToken="+ token;
String response = HttpUtils.sendPost(url, token);
}
} }