Skip to content

Commit

Permalink
[Feature-1620][feat] Integrate Casdoor for SSO
Browse files Browse the repository at this point in the history
    add casdoor login support SSO

This closes DataLinkDC#1620
  • Loading branch information
gaopeng666 committed Aug 21, 2023
1 parent 6e73703 commit 07f6251
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 2 deletions.
4 changes: 4 additions & 0 deletions dinky-admin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@
<artifactId>jsqlparser</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.casbin</groupId>
<artifactId>casdoor-spring-boot-starter</artifactId>
</dependency>

<!-- test dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public void addInterceptors(InterceptorRegistry registry) {
.addPathPatterns("/api/**")
.excludePathPatterns(
"/api/login", "/api/ldap/ldapEnableStatus",
"/api/getCasdoorUrl", "/api/loginWithCasdoor",
"/druid/**", "/openapi/**");

registry.addInterceptor(new TenantInterceptor())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
import org.dinky.service.UserService;
import org.dinky.utils.I18nMsgUtils;

import javax.servlet.http.HttpServletRequest;

import org.casbin.casdoor.service.CasdoorAuthService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
Expand Down Expand Up @@ -56,6 +59,8 @@ public class AdminController {

private final UserService userService;

private final CasdoorAuthService casdoorAuthService;

/**
* user login
*
Expand All @@ -68,6 +73,33 @@ public Result<UserDTO> login(@RequestBody LoginDTO loginDTO) {
return userService.loginUser(loginDTO);
}

/**
* get casdoor login url
*
* @param request
* @return redirect address
*/
@PostMapping("/getCasdoorUrl")
@ApiOperation("Get Casdoor Url")
public Result<String> getCasdoorUrl(HttpServletRequest request) {
String origin = request.getParameter("origin");
String url = casdoorAuthService.getSigninUrl(origin);
return Result.succeed(url, "Get Url successful");
}

/**
* user login with casdoor
*
* @param code
* @param state
* @return {@link Result}{@link UserDTO} obtain the user's UserDTO
*/
@PostMapping("/loginWithCasdoor")
@ApiOperation("loginWithCasdoor")
public Result<UserDTO> loginWithCasdoor(@RequestParam("code") String code, @RequestParam("state") String state) {
return userService.loginCasdoorUser(code, state);
}

/**
* user logout
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.dinky.data.enums;

public enum UserType {
CASDOOR(2, "CASDOOR"),
LDAP(1, "LDAP"),
LOCAL(0, "LOCAL");

Expand Down
9 changes: 9 additions & 0 deletions dinky-admin/src/main/java/org/dinky/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ public interface UserService extends ISuperService<User> {
*/
Result<UserDTO> loginUser(LoginDTO loginDTO);

/**
* loginCasdoorUser
*
* @param code
* @param state
* @return {@link Result}{@link UserDTO} obtain the user's UserDTO
*/
Result<UserDTO> loginCasdoorUser(String code, String state);

/**
* getUserByUsername
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
import java.util.List;
import java.util.stream.Collectors;

import org.casbin.casdoor.entity.CasdoorUser;
import org.casbin.casdoor.service.CasdoorAuthService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -95,6 +97,8 @@ public class UserServiceImpl extends SuperServiceImpl<UserMapper, User> implemen

private final MenuService menuService;

private final CasdoorAuthService casdoorAuthService;

@Override
public Result<Void> registerUser(User user) {
User userByUsername = getUserByUsername(user.getUsername());
Expand Down Expand Up @@ -152,7 +156,7 @@ public Boolean removeUser(Integer id) {
*
* @param loginDTO a user based on the provided login credentials.
* @return a Result object containing the user information if the login is successful, or an
* appropriate error status if the login fails.
* appropriate error status if the login fails.
*/
@Override
public Result<UserDTO> loginUser(LoginDTO loginDTO) {
Expand Down Expand Up @@ -187,6 +191,77 @@ public Result<UserDTO> loginUser(LoginDTO loginDTO) {
return Result.succeed(userInfo, Status.LOGIN_SUCCESS);
}

@Override
public Result<UserDTO> loginCasdoorUser(String code, String state) {
User user = null;
try {
user = casdoorLogin(code, state);
} catch (AuthException e) {
return Result.failed(e.getStatus() + e.getMessage());
}

// Check if the user is enabled
if (!user.getEnabled()) {
loginLogService.saveLoginLog(user, Status.USER_DISABLED_BY_ADMIN);
return Result.failed(Status.USER_DISABLED_BY_ADMIN);
}

UserDTO userInfo = refreshUserInfo(user);
if (Asserts.isNullCollection(userInfo.getTenantList())) {
loginLogService.saveLoginLog(user, Status.USER_NOT_BINDING_TENANT);
return Result.failed(Status.USER_NOT_BINDING_TENANT);
}

// Perform login using StpUtil (Assuming it handles the session management)
StpUtil.login(user.getId());

// save login log record
loginLogService.saveLoginLog(user, Status.LOGIN_SUCCESS);

// Return the user information along with a success status
return Result.succeed(userInfo, Status.LOGIN_SUCCESS);
}

private User casdoorLogin(String code, String state) throws AuthException {
User userFromCasdoor = null;
String token = casdoorAuthService.getOAuthToken(code, state);
CasdoorUser casdoorUser = casdoorAuthService.parseJwtToken(token);
if (casdoorUser.getName() != null) {
userFromCasdoor = new User();
userFromCasdoor.setUsername(casdoorUser.getName());
userFromCasdoor.setNickname(casdoorUser.getDisplayName());
} else {
throw new AuthException(Status.STATE_CODE_ERROR);
}
// Get user from local database
User userFromLocal = getUserByUsername(casdoorUser.getName());

if (Asserts.isNull(userFromLocal)) {
String defaultTeantCode =
SystemConfiguration.getInstances().getCasdoorDefaultTeant().getValue();
Tenant tenant = tenantService.getTenantByTenantCode(defaultTeantCode);
if (Asserts.isNull(tenant)) {
loginLogService.saveLoginLog(userFromLocal, Status.CASDOOR_DEFAULT_TENANT_NOFOUND);
throw new AuthException(Status.CASDOOR_DEFAULT_TENANT_NOFOUND);
}

// Update Casdoor user properties and save
userFromCasdoor.setUserType(UserType.CASDOOR.getCode());
userFromCasdoor.setEnabled(true);
userFromCasdoor.setSuperAdminFlag(false);
userFromCasdoor.setIsDelete(false);
save(userFromCasdoor);

// Assign the user to the default tenant
List<Integer> userIds = getUserIdsByTenantId(tenant.getId());
User user = getUserByUsername(casdoorUser.getName());
userIds.add(user.getId());
tenantService.assignUserToTenant(new AssignUserToTenantParams(tenant.getId(), userIds));
return user;
}
return userFromLocal;
}

private User localLogin(LoginDTO loginDTO) throws AuthException {
// Get user from local database by username
User user = getUserByUsername(loginDTO.getUsername());
Expand Down
2 changes: 2 additions & 0 deletions dinky-common/src/main/java/org/dinky/data/enums/Status.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public enum Status {
KICK_OUT(10024, "token has been kicked offline", "token 已被踢下线"),
TOKEN_FREEZED(10025, "token has been frozen", "token 已被冻结"),
NO_PREFIX(10026, "The token was not submitted according to the specified prefix", "未按照指定前缀提交 token"),
STATE_CODE_ERROR(10027, "state inconsistency or state and code not pair", "状态码前后不一致或状态码和code不匹配"),
CASDOOR_DEFAULT_TENANT_NOFOUND(10028, "The Casdoor default tenant does not exist", "casdoor默认租户不存在"),

// role
ROLE_ALREADY_EXISTS(10101, "Role Already Exists", "角色已存在"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ public static Configuration.OptionBuilder key(String key) {
private final Configuration<Boolean> ldapEnable =
key("ldap.settings.enable").booleanType().defaultValue(false).note("LDAP ON-OFF");

private final Configuration<String> casdoorDefaultTeant = key("casdoor.settings.defaultTeant")
.stringType()
.defaultValue("DefaultTenant")
.note("casdoor default default teant code");

private final Configuration<Boolean> metricsSysEnable = key("metrics.settings.sys.enable")
.booleanType()
.defaultValue(false)
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
<spotless.ratchetFrom>origin/dev</spotless.ratchetFrom>
<spotless.version>2.27.1</spotless.version>
<spring-boot-dependencies.version>2.7.11</spring-boot-dependencies.version>
<spring.casdoor.version>1.6.0</spring.casdoor.version>
<spring.ldap.version>3.1.0</spring.ldap.version>
<target.java.version>8</target.java.version>
<testcontainers.version>1.16.2</testcontainers.version>
Expand Down Expand Up @@ -642,6 +643,11 @@
<artifactId>spring-boot-starter-data-ldap</artifactId>
<version>${spring.ldap.version}</version>
</dependency>
<dependency>
<groupId>org.casbin</groupId>
<artifactId>casdoor-spring-boot-starter</artifactId>
<version>${spring.casdoor.version}</version>
</dependency>

</dependencies>
</dependencyManagement>
Expand Down
2 changes: 1 addition & 1 deletion script/sql/dinky-mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ CREATE TABLE `dinky_sys_login_log` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'key',
`user_id` int NOT NULL COMMENT 'user id',
`username` varchar(60) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'username',
`login_type` int NOT NULL COMMENT 'login type(0:LOCAL,1:LDAP',
`login_type` int NOT NULL COMMENT 'login type(0:LOCAL,1:ldap,2:Casdoor',
`ip` varchar(40) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ip addr',
`status` int NOT NULL COMMENT 'login status',
`msg` text COLLATE utf8mb4_general_ci NOT NULL COMMENT 'status msg',
Expand Down

0 comments on commit 07f6251

Please sign in to comment.