feat: add support for Casdoor authentication (#39)
diff --git a/backend/pom.xml b/backend/pom.xml index fb5d805..a7d67a9 100644 --- a/backend/pom.xml +++ b/backend/pom.xml
@@ -145,6 +145,12 @@ </dependency> <dependency> + <groupId>org.casbin</groupId> + <artifactId>casdoor-spring-boot-starter</artifactId> + <version>1.3.0</version> + </dependency> + + <dependency> <groupId>org.apache.iotdb</groupId> <artifactId>iotdb-session</artifactId> <version>0.12.5</version>
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java index 93adb9a..9a001b1 100644 --- a/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java +++ b/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java
@@ -33,6 +33,8 @@ import io.jsonwebtoken.Claims; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.casbin.casdoor.entity.CasdoorUser; +import org.casbin.casdoor.service.CasdoorAuthService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -53,6 +55,8 @@ private static final Logger logger = LoggerFactory.getLogger(UserController.class); + @Autowired private CasdoorAuthService casdoorAuthService; + @PostMapping("/login") @ApiOperation("login") public BaseVO<ConnectionVO> login( @@ -71,6 +75,35 @@ return BaseVO.success("Login successful", connectionVO); } + @PostMapping("/getCasdoorUrl") + @ApiOperation("Get Casdoor Url") + public BaseVO<String> getCasdoorUrl(HttpServletRequest request, HttpServletResponse response) + throws BaseException { + String origin = request.getParameter("origin"); + String url = casdoorAuthService.getSigninUrl(origin); + return BaseVO.success("Get Url successful", url); + } + + @PostMapping("/loginWithCasdoor") + @ApiOperation("loginWithCasdoor") + public BaseVO<ConnectionVO> loginWithCasdoor( + @RequestParam("code") String code, + @RequestParam("state") String state, + HttpServletResponse response) + throws BaseException { + String token = casdoorAuthService.getOAuthToken(code, state); + CasdoorUser casdoorUser = casdoorAuthService.parseJwtToken(token); + User user = new User(); + user.setId(casdoorUser.getRanking()); + user.setName(casdoorUser.getName()); + int userId = user.getId(); + String name = user.getName(); + List<ConnVO> connVOs = connectionService.getAllConnections(userId); + ConnectionVO connectionVO = new ConnectionVO(connVOs, userId, name); + response.addHeader("Authorization", JJwtTool.generateToken(user)); + return BaseVO.success("Login successful", connectionVO); + } + @PostMapping("/save") @ApiOperation("Create user (not used)") public BaseVO save(@RequestBody User user) throws BaseException {
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index e9e7335..e3fdf60 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties
@@ -18,4 +18,11 @@ # # Designate the configuration file -spring.profiles.active=dev \ No newline at end of file +spring.profiles.active=dev + +casdoor.endpoint = +casdoor.clientId = +casdoor.clientSecret = +casdoor.certificate = +casdoor.organizationName = +casdoor.applicationName = \ No newline at end of file
diff --git a/frontend/.env b/frontend/.env new file mode 100644 index 0000000..de09d64 --- /dev/null +++ b/frontend/.env
@@ -0,0 +1 @@ +VUE_APP_CASDOOR=false \ No newline at end of file
diff --git a/frontend/src/i18n/cn.js b/frontend/src/i18n/cn.js index 03d2620..63ec22b 100644 --- a/frontend/src/i18n/cn.js +++ b/frontend/src/i18n/cn.js
@@ -86,6 +86,7 @@ placeholderPassword: '请输入密码', forgetPassWord: '忘记密码', signIn: '登录', + signInWithCasdoor: 'Casdoor登录', forgetPassword: '忘记密码', forgetPasswordTip: '请联系系统管理员 WeChat:loveher147', accountEmptyTip: '账号不能为空',
diff --git a/frontend/src/i18n/de.js b/frontend/src/i18n/de.js index 6634c75..b988b5a 100644 --- a/frontend/src/i18n/de.js +++ b/frontend/src/i18n/de.js
@@ -85,6 +85,7 @@ placeholderPassword: 'Passwort eingeben', forgetPassWord: 'Passwort vergessen', signIn: 'Anmelden', + signInWithCasdoor: 'Loggen Sie sich mit casdoor ein', forgetPassword: 'Passwort vergessen', forgetPasswordTip: 'Bitte kontaktieren Sie Ihren Administrator WeChat:loveher147', accountEmptyTip: 'Benutzername darf nicht leer sein',
diff --git a/frontend/src/i18n/en.js b/frontend/src/i18n/en.js index 87113a6..4008863 100644 --- a/frontend/src/i18n/en.js +++ b/frontend/src/i18n/en.js
@@ -85,6 +85,7 @@ placeholderPassword: 'Please Input Password', forgetPassWord: 'Forget Password', signIn: 'Sign In', + signInWithCasdoor: 'Sign In With Casdoor', forgetPassword: 'Forget Password', forgetPasswordTip: 'Please Contact System Administrator WeChat:loveher147', accountEmptyTip: 'Account Can Not Be Empty',
diff --git a/frontend/src/util/axios.js b/frontend/src/util/axios.js index 193f878..e44c18f 100644 --- a/frontend/src/util/axios.js +++ b/frontend/src/util/axios.js
@@ -22,7 +22,7 @@ import router from '../router'; const instance = axios.create({}); -const headerUrls = ['/api/login', '/api/downloadFile/template', '/api/downloadQueryLogFile']; +const headerUrls = ['/api/login', '/api/loginWithCasdoor', '/api/downloadFile/template', '/api/downloadQueryLogFile']; const exportUrl = '/exportData'; const downUrl = '/downloadFile'; instance.defaults.withCredentials = true;
diff --git a/frontend/src/views/Login/index.vue b/frontend/src/views/Login/index.vue index 3b18b4f..3dd06f2 100644 --- a/frontend/src/views/Login/index.vue +++ b/frontend/src/views/Login/index.vue
@@ -60,6 +60,9 @@ <el-button class="submit-btn" type="primary" @click="submitForm('ruleForm')">{{ $t('loginPage.signIn') }}</el-button> </el-form-item> </el-form> + <el-form-item v-if="casdoorSwitch === 'true'"> + <el-button class="submit-btn" type="primary" @click="getLoginUrl()">{{ $t('loginPage.signInWithCasdoor') }}</el-button> + </el-form-item> </div> </div> </div> @@ -90,6 +93,7 @@ const formNameRef = ref(null); const dialogVisible = ref(false); const { t } = useI18n(); + const casdoorSwitch = process.env.VUE_APP_CASDOOR; const ruleForm = reactive({ account: '', passport: '', @@ -145,6 +149,7 @@ // if (store.state.isLogin) { // router.push({ name: "Root" }); // } + LoginWithCasdoor(); }); const submitForm = () => { @@ -164,6 +169,31 @@ }); }; + const getLoginUrl = () => { + axios.post('/getCasdoorUrl', {}, { params: { origin: window.location.origin } }).then((res) => { + window.location.href = res.data; + }); + }; + + const LoginWithCasdoor = () => { + const url = window.document.location.href; + const u = new URL(url); + let codes = u.searchParams.get('code'); + let state = u.searchParams.get('state'); + if (codes != null && state != null) { + axios.post('/loginWithCasdoor', {}, { params: { code: codes, state: state } }).then((res) => { + if (res?.data?.code === '0') { + localStorage.setItem('authorization', res?.headers?.authorization); + store.commit('setLogin', true); + store.commit('setUserInfo', res.data || {}); + router.push({ name: 'Root' }); + } else { + ElMessage.error(t(`loginPage.loginErrorTip`)); + } + }); + } + }; + const showDialog = () => { dialogVisible.value = true; }; @@ -177,6 +207,9 @@ rules, submitForm, showDialog, + getLoginUrl, + LoginWithCasdoor, + casdoorSwitch, }; }, components: { ElForm, ElFormItem, ElInput, ElButton, ElDialog, ElDropdown, ElDropdownMenu, ElDropdownItem },