RuoYi
Casdoor可以轻松地与RuoYi-cloud集成。
步骤1:部署Casdoor
首先,部署Casdoor。
您可以参考Casdoor 官方文档 Server Installation 。
部署成功后,请确保以下内容:
- Casdoor 服务器正在运行于 http://localhost:8000。
- 打开你最喜欢的浏览器,访问 http://localhost:7001 来访问Casdoor登录页面。
- 通过输入
admin
和123
来测试登录功能。
接下来,你可以按照以下步骤在你自己的应用中快速实现一个基于Casdoor的登录页面。
步骤2:配置Casdoor
要配置Casdoor,请按照以下步骤操作:
以下是一些需要记住的额外要点:
编辑同步器时,请务必检查表格列:。
在编辑组织时,确保选择正确的密码类型:。
最后,确保你已启用软删除。
请确保仔细遵循这些指示,以正确配置Casdoor。
步骤3. 前端改造
3.1 跳转到Casdoor的登录页面
我们可以使用一个前端SDK,以vue-sdk为例。 在你初始化 vue-sdk 之后,你可以通过使用 getSigninUrl() 函数来获取 Casdoor 登录页面的 URL。
您可以按照您喜欢的方式进行链接,并随时删除Ruoyi-Cloud中不再需要的任何原始代码,例如原始的账户和密码el-input。
3.2 接受Casdoor返回的代码和状态
通过Casdoor成功登录后,Casdoor会将代码和状态发送到我们设置的页面。 我们可以使用create()函数来获取代码和状态。
created() {
let url = window.document.location.href; // 获取URL
let u = new URL(url);
this.loginForm.code = u.searchParams.get('code'); // 获取code和state
this.loginForm.state = u.searchParams.get('state');
if (this.loginForm.code != null && this.loginForm.state != null) { // 如果code和state不为null,执行handleLogin
this.handleLogin();
}
}
对于RuoYi-Cloud,我们只需修改其原来的发送账号和密码的方法,改为发送代码和状态。 因此,变化仅在于与原始登录相关的发送到后端的内容。
步骤4:重构你的后端
4.1 接受前端返回的代码和状态
@PostMapping("login")
public R<?> callback(@RequestBody CodeBody code) {
String token = casdoorAuthService.getOAuthToken(code.getCode(), code.getState());
CasdoorUser casdoorUser = casdoorAuthService.parseJwtToken(token);
如果 (casdoorUser.getName() != null) {
String casdoorUserName = casdoorUser.getName();
如果 (sysLoginService.getUserByCasdoorName(casdoorUserName) == null) {
sysLoginService.casdoorRegister(casdoorUserName); // 如果用户不存在,则将此用户添加到数据库中
}
}
LoginUser userInfo = sysLoginService.casdoorLogin(casdoorUser.getName()); // 从数据库获取用户的信息
return R.ok(tokenService.createToken(userInfo));
}
在这个方法中,我们使用了casdoor-SpringBoot-sdk方法,并对RuoYi-Cloud方法进行了轻微的修改。
例如,RuoYi-Cloud原始方法使用密码注册账户。 我已将其更改为使用casdoorRegister
方法注册账户。
我还添加了一个方法getUserByCasdoorName
来检查账户是否存在,并将方法executeUserInfo
更改为executeWithAccount
以反映这一变化。
这是一个简单的修改,因为我们只需要删除检查密码的部分。
步骤5:总结
5.1 前端
- 需要移除现有的登录和注册页面。
- 此外,前端需要接受代码和状态参数,并将它们发送到后端。
5.2 后端
RuoYi后端已经实现了完善的登录和注册功能。 我们只需要做一些小修改,这使得整个过程非常方便。
步骤6:详细步骤
部署并配置Casdoor。 确保为组织选择bcrypt密码类型,因为RuoYi-Cloud也使用bcrypt来处理密码。
使用Casdoor同步器将数据库用户复制到您的Casdoor组织。 这将把原始账户导入到Casdoor。
部署Casdoor后,对前端进行更改。 禁用 RuoYi 检查代码。
请注意,RuoYi-Cloud的验证码需要再次在Nacos中禁用。 另外,RuoYi-Cloud的注册功能需要通过设置
sys.account.registerUser
为true
来启用。为用户添加一个用Casdoor登录的按钮,并修改数据的
loginForm
。这里,我已经写下了URL,但你可以使用Casdoor-Vue-SDK或Casdoor-SpringBoot-SDK来获取它。
由于我们不再使用原始的登录方法,删除cookie和checkcode方法。
新的
created
函数应该如下所示:created() {
let url = window.document.location.href; // 获取URL
let u = new URL(url);
this.loginForm.code = u.searchParams.get('code'); // 获取code和state
this.loginForm.state = u.searchParams.get('state');
if (this.loginForm.code != null && this.loginForm.state != null) { // 如果code和state不为null,执行handleLogin
this.handleLogin();
}
}事实上,我们只需要更改我们发送到后端的参数,并删除不必要的函数。 不需要进行其他更改。
在后端导入所需的依赖项。
pom.xml<dependency>
<groupId>org.casbin</groupId>
<artifactId>casdoor-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>您还需要在资源文件中配置Casdoor。
将回调函数定义为重定向函数。 对
sysLoginService
中的一些方法进行更改。 删除密码检查步骤,因为它不再需要。@PostMapping("login")
public R<?> callback(@RequestBody CodeBody code) {
// 定义一个带有code和state的CodeBody实体
String token = casdoorAuthService.getOAuthToken(code.getCode(), code.getState());
CasdoorUser casdoorUser = casdoorAuthService.parseJwtToken(token);
if (casdoorUser.getName() != null) {
String casdoorUserName = casdoorUser.getName();
if (sysLoginService.getUserByCasdoorName(casdoorUserName) == null) {
// 如果用户不在RuoYi-Cloud数据库中,但在Casdoor中存在,则在数据库中创建用户
sysLoginService.casdoorRegister(casdoorUserName);
}
}
LoginUser userInfo = sysLoginService.casdoorLogin(casdoorUser.getName());
// 从数据库获取用户的信息
return R.ok(tokenService.createToken(userInfo));
}向
SysLoginService
添加新方法。public LoginUser casdoorLogin(String username) {
R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
// 执行用户
if (R.FAIL == userResult.getCode()) {
throw new ServiceException(userResult.getMsg());
}
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) {
recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "该用户不存在");
throw new ServiceException("用户 " + username + " 不存在");
}
LoginUser userInfo = userResult.getData();
SysUser user = userResult.getData().getSysUser();
if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账户已被删除");
throw new ServiceException("对不起,您的账户 " + username + " 已被删除");
}
if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "您的账户已被禁用. 请联系管理员");
throw new ServiceException("对不起,您的账户 " + username + " 已被禁用");
}
recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
return userInfo;
}public String getUserByCasdoorName(String casdoorUsername) {
R<LoginUser> userResult = remoteUserService.getUserInfo(casdoorUsername, SecurityConstants.INNER);
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData())) {
// 如果用户不在RuoYi-Cloud数据库中,但在Casdoor中存在,则在数据库中创建用户
return null;
}
String username = userResult.getData().getSysUser().getUserName();
return username;
}public void casdoorRegister(String username) {
if (StringUtils.isAnyBlank(username)) {
throw new ServiceException("用户必须提供用户名");
}
SysUser sysUser = new SysUser();
sysUser.setUserName(username);
sysUser.setNickName(username);
R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);
System.out.println(registerResult);
if (R.FAIL == registerResult.getCode()) {
throw new ServiceException(registerResult.getMsg());
}
recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功");
}