跳到主内容

RuoYi

Casdoor可以轻松地与RuoYi-cloud集成。

步骤1:部署Casdoor

首先,部署Casdoor。

您可以参考Casdoor 官方文档 Server Installation

部署成功后,请确保以下内容:

接下来,你可以按照以下步骤在你自己的应用中快速实现一个基于Casdoor的登录页面。

步骤2:配置Casdoor

要配置Casdoor,请按照以下步骤操作:

  1. 通过点击这里在浏览器中打开Casdoor。 建议使用与您的开发浏览器不同的浏览器。

  2. 在Casdoor中配置一个组织,一个应用程序和同步器。 您可以在这里找到详细的操作指南。

以下是一些需要记住的额外要点:

  1. 编辑同步器时,请务必检查表格列:Table Columns

  2. 在编辑组织时,确保选择正确的密码类型:Password Type

  3. 最后,确保你已启用软删除。

请确保仔细遵循这些指示,以正确配置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:详细步骤

  1. 部署并配置Casdoor。 确保为组织选择bcrypt密码类型,因为RuoYi-Cloud也使用bcrypt来处理密码。

  2. 使用Casdoor同步器将数据库用户复制到您的Casdoor组织。 这将把原始账户导入到Casdoor。

  3. 部署Casdoor后,对前端进行更改。 禁用 RuoYi 检查代码。

    校验码切换

    请注意,RuoYi-Cloud的验证码需要再次在Nacos中禁用。 另外,RuoYi-Cloud的注册功能需要通过设置sys.account.registerUsertrue来启用。

  4. 为用户添加一个用Casdoor登录的按钮,并修改数据的loginForm

    登录按钮 登录表单数据 这里,我已经写下了URL,但你可以使用Casdoor-Vue-SDK或Casdoor-SpringBoot-SDK来获取它。

  5. 由于我们不再使用原始的登录方法,删除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();
    }
    }
  6. 事实上,我们只需要更改我们发送到后端的参数,并删除不必要的函数。 不需要进行其他更改。

    处理登录 登录 登录

  7. 在后端导入所需的依赖项。

    pom.xml
    <dependency>
    <groupId>org.casbin</groupId>
    <artifactId>casdoor-spring-boot-starter</artifactId>
    <version>1.2.0</version>
    </dependency>

    您还需要在资源文件中配置Casdoor。

  8. 将回调函数定义为重定向函数。 对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));
    }
  9. 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, "注册成功");
    }