mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-07-23 01:29:34 +08:00
接入sa-token
This commit is contained in:
parent
5005e76b81
commit
c9371b0589
19
pom.xml
19
pom.xml
@ -138,6 +138,25 @@
|
||||
<version>5.8.16</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>1.34.0</version>
|
||||
</dependency>
|
||||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>1.34.0</version>
|
||||
</dependency>
|
||||
<!-- Sa-Token 整合 jwt -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-jwt</artifactId>
|
||||
<version>1.34.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
|
@ -19,11 +19,6 @@ import xyz.playedu.api.domain.User;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/13 09:24
|
||||
*/
|
||||
public class FCtx {
|
||||
private static final java.lang.ThreadLocal<LinkedHashMap<String, Object>> THREAD_LOCAL =
|
||||
new java.lang.ThreadLocal<>();
|
||||
|
@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.types;
|
||||
package xyz.playedu.api.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@Data
|
||||
public class JwtToken {
|
||||
|
||||
private String token;
|
||||
|
||||
private Long expire;
|
||||
public class AuthConfig {
|
||||
@Value("${sa-token.timeout}")
|
||||
private Integer expired;
|
||||
}
|
31
src/main/java/xyz/playedu/api/config/SaTokenConfigure.java
Normal file
31
src/main/java/xyz/playedu/api/config/SaTokenConfigure.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 杭州白书科技有限公司
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.config;
|
||||
|
||||
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SaTokenConfigure {
|
||||
// Sa-Token 整合 jwt (Simple 简单模式)
|
||||
@Bean
|
||||
public StpLogic getStpLogicJwt() {
|
||||
return new StpLogicJwtForSimple();
|
||||
}
|
||||
}
|
@ -37,11 +37,11 @@ import java.util.List;
|
||||
@Slf4j
|
||||
public class ExceptionController {
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public JsonResponse exceptionHandler(Exception e) {
|
||||
log.error(e.getMessage());
|
||||
return JsonResponse.error("系统错误", 500);
|
||||
}
|
||||
// @ExceptionHandler(Exception.class)
|
||||
// public JsonResponse exceptionHandler(Exception e) {
|
||||
// log.error(e.getMessage());
|
||||
// return JsonResponse.error("系统错误", 500);
|
||||
// }
|
||||
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public JsonResponse serviceExceptionHandler(ServiceException e) {
|
||||
|
@ -23,7 +23,6 @@ import org.springframework.web.bind.annotation.*;
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.bus.BackendBus;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.event.AdminUserLoginEvent;
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
@ -32,9 +31,8 @@ import xyz.playedu.api.middleware.ImageCaptchaCheckMiddleware;
|
||||
import xyz.playedu.api.request.backend.LoginRequest;
|
||||
import xyz.playedu.api.request.backend.PasswordChangeRequest;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.service.BackendAuthService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.IpUtil;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
@ -49,7 +47,7 @@ public class LoginController {
|
||||
|
||||
@Autowired private BackendBus backendBus;
|
||||
|
||||
@Autowired private JWTService jwtService;
|
||||
@Autowired private BackendAuthService authService;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@ -69,19 +67,16 @@ public class LoginController {
|
||||
return JsonResponse.error("当前用户已禁止登录");
|
||||
}
|
||||
|
||||
String url = RequestUtil.url();
|
||||
JwtToken token =
|
||||
jwtService.generate(adminUser.getId(), url, SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
String token = authService.loginUsingId(adminUser.getId(), RequestUtil.url());
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("token", token.getToken());
|
||||
data.put("expire", token.getExpire());
|
||||
data.put("token", token);
|
||||
|
||||
ctx.publishEvent(
|
||||
new AdminUserLoginEvent(
|
||||
this,
|
||||
adminUser.getId(),
|
||||
token.getToken(),
|
||||
token,
|
||||
IpUtil.getIpAddress(),
|
||||
adminUser.getLoginTimes()));
|
||||
|
||||
@ -90,7 +85,7 @@ public class LoginController {
|
||||
|
||||
@PostMapping("/logout")
|
||||
public JsonResponse logout() throws JwtLogoutException {
|
||||
jwtService.adminUserLogout(RequestUtil.token());
|
||||
authService.logout();
|
||||
return JsonResponse.success("success");
|
||||
}
|
||||
|
||||
|
@ -24,36 +24,28 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.playedu.api.FCtx;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.User;
|
||||
import xyz.playedu.api.event.UserLoginEvent;
|
||||
import xyz.playedu.api.event.UserLogoutEvent;
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.exception.LimitException;
|
||||
import xyz.playedu.api.middleware.ImageCaptchaCheckMiddleware;
|
||||
import xyz.playedu.api.request.frontend.LoginPasswordRequest;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.service.FrontendAuthService;
|
||||
import xyz.playedu.api.service.UserService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.IpUtil;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/2 21:51
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/auth/login")
|
||||
public class LoginController {
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@Autowired private JWTService jwtService;
|
||||
@Autowired private FrontendAuthService authService;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@ -74,19 +66,17 @@ public class LoginController {
|
||||
return JsonResponse.error("当前学员已锁定无法登录");
|
||||
}
|
||||
|
||||
JwtToken token =
|
||||
jwtService.generate(user.getId(), RequestUtil.url(), SystemConstant.JWT_PRV_USER);
|
||||
String token = authService.loginUsingId(user.getId(), RequestUtil.url());
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("token", token.getToken());
|
||||
data.put("expired", token.getExpire());
|
||||
data.put("token", token);
|
||||
|
||||
ctx.publishEvent(
|
||||
new UserLoginEvent(
|
||||
this,
|
||||
user.getId(),
|
||||
user.getEmail(),
|
||||
token.getToken(),
|
||||
token,
|
||||
IpUtil.getIpAddress(),
|
||||
RequestUtil.ua()));
|
||||
|
||||
@ -94,8 +84,8 @@ public class LoginController {
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public JsonResponse logout() throws JwtLogoutException {
|
||||
jwtService.userLogout(RequestUtil.token());
|
||||
public JsonResponse logout() {
|
||||
authService.logout();
|
||||
ctx.publishEvent(new UserLogoutEvent(this, FCtx.getId(), FCtx.getJwtJti()));
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
@ -66,8 +66,11 @@ public class UserController {
|
||||
@GetMapping("/detail")
|
||||
public JsonResponse detail() {
|
||||
User user = FCtx.getUser();
|
||||
List<Department> departments =
|
||||
departmentService.listByIds(userService.getDepIdsByUserId(user.getId()));
|
||||
List<Department> departments = new ArrayList<>();
|
||||
List<Integer> depIds = userService.getDepIdsByUserId(user.getId());
|
||||
if (depIds != null && depIds.size() > 0) {
|
||||
departmentService.listByIds(depIds);
|
||||
}
|
||||
|
||||
user.setIdCard(PrivacyUtil.hideIDCard(user.getIdCard()));
|
||||
|
||||
|
@ -22,36 +22,34 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.event.UserLoginEvent;
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.service.FrontendAuthService;
|
||||
import xyz.playedu.api.service.UserLoginRecordService;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.util.IpUtil;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/10 13:45
|
||||
*/
|
||||
import java.util.HashMap;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class UserLoginListener {
|
||||
|
||||
@Autowired private UserLoginRecordService loginRecordService;
|
||||
|
||||
@Autowired private JWTService jwtService;
|
||||
@Autowired private FrontendAuthService authService;
|
||||
|
||||
@Async
|
||||
@EventListener
|
||||
public void updateLoginInfo(UserLoginEvent event) throws JwtLogoutException {
|
||||
public void updateLoginInfo(UserLoginEvent event) {
|
||||
String ipArea = IpUtil.getRealAddressByIP(event.getIp());
|
||||
JWTPayload payload = jwtService.parse(event.getToken(), SystemConstant.JWT_PRV_USER);
|
||||
|
||||
HashMap<String, String> tokenData = authService.parse(event.getToken());
|
||||
String jti = tokenData.get("jti");
|
||||
Long exp = Long.parseLong(tokenData.get("exp"));
|
||||
|
||||
loginRecordService.store(
|
||||
event.getUserId(),
|
||||
payload.getJti(),
|
||||
payload.getExp(),
|
||||
jti,
|
||||
exp,
|
||||
event.getIp(),
|
||||
ipArea,
|
||||
event.getUserAgent().getBrowser().toString(),
|
||||
|
@ -27,15 +27,12 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.bus.AppBus;
|
||||
import xyz.playedu.api.bus.BackendBus;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.service.AppConfigService;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.service.BackendAuthService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
@ -44,7 +41,7 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
public class AdminMiddleware implements HandlerInterceptor {
|
||||
|
||||
@Autowired private JWTService jwtService;
|
||||
@Autowired private BackendAuthService authService;
|
||||
|
||||
@Autowired private AdminUserService adminUserService;
|
||||
|
||||
@ -70,33 +67,23 @@ public class AdminMiddleware implements HandlerInterceptor {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
String token = RequestUtil.token();
|
||||
if (token.length() == 0) {
|
||||
if (!authService.check()) {
|
||||
return responseTransform(response, 401, "请登录");
|
||||
}
|
||||
|
||||
try {
|
||||
JWTPayload payload = jwtService.parse(token, SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
|
||||
AdminUser adminUser = adminUserService.findById(payload.getSub());
|
||||
if (adminUser == null) {
|
||||
return responseTransform(response, 401, "管理员不存在");
|
||||
}
|
||||
if (adminUser.getIsBanLogin() == 1) {
|
||||
return responseTransform(response, 403, "当前管理员禁止登录");
|
||||
}
|
||||
|
||||
BCtx.setId(payload.getSub());
|
||||
BCtx.setAdminUser(adminUser);
|
||||
BCtx.setAdminPer(backendBus.adminUserPermissions(adminUser.getId()));
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
} catch (Exception e) {
|
||||
if (appBus.isDev()) {
|
||||
log.debug("jwt解析失败:" + e.getMessage());
|
||||
}
|
||||
return responseTransform(response, 401, "请重新登录");
|
||||
AdminUser adminUser = adminUserService.findById(authService.userId());
|
||||
if (adminUser == null) {
|
||||
return responseTransform(response, 401, "管理员不存在");
|
||||
}
|
||||
if (adminUser.getIsBanLogin() == 1) {
|
||||
return responseTransform(response, 403, "当前管理员禁止登录");
|
||||
}
|
||||
|
||||
BCtx.setId(authService.userId());
|
||||
BCtx.setAdminUser(adminUser);
|
||||
BCtx.setAdminPer(backendBus.adminUserPermissions(adminUser.getId()));
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
private boolean responseTransform(HttpServletResponse response, int code, String msg)
|
||||
|
@ -26,27 +26,19 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import xyz.playedu.api.FCtx;
|
||||
import xyz.playedu.api.constant.FrontendConstant;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.User;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.service.FrontendAuthService;
|
||||
import xyz.playedu.api.service.UserService;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/13 09:40
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FrontMiddleware implements HandlerInterceptor {
|
||||
|
||||
@Autowired private JWTService jwtService;
|
||||
@Autowired private FrontendAuthService authService;
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@ -62,31 +54,23 @@ public class FrontMiddleware implements HandlerInterceptor {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
String token = RequestUtil.token();
|
||||
if (token.length() == 0) {
|
||||
if (!authService.check()) {
|
||||
return responseTransform(response, 401, "请登录");
|
||||
}
|
||||
|
||||
try {
|
||||
JWTPayload payload = jwtService.parse(token, SystemConstant.JWT_PRV_USER);
|
||||
|
||||
User user = userService.find(payload.getSub());
|
||||
if (user == null) {
|
||||
return responseTransform(response, 401, "请重新登录");
|
||||
}
|
||||
if (user.getIsLock() == 1) {
|
||||
return responseTransform(response, 403, "当前学员已锁定无法登录");
|
||||
}
|
||||
|
||||
FCtx.setUser(user);
|
||||
FCtx.setId(user.getId());
|
||||
FCtx.setJWtJti(payload.getJti());
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
User user = userService.find(authService.userId());
|
||||
if (user == null) {
|
||||
return responseTransform(response, 401, "请重新登录");
|
||||
}
|
||||
if (user.getIsLock() == 1) {
|
||||
return responseTransform(response, 403, "当前学员已锁定无法登录");
|
||||
}
|
||||
|
||||
FCtx.setUser(user);
|
||||
FCtx.setId(user.getId());
|
||||
FCtx.setJWtJti(authService.jti());
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
private boolean responseTransform(HttpServletResponse response, int code, String msg)
|
||||
|
@ -13,34 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.types;
|
||||
package xyz.playedu.api.service;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @see https://www.rfc-editor.org/rfc/rfc7519#section-4.1
|
||||
*/
|
||||
@Data
|
||||
public class JWTPayload {
|
||||
public interface AuthService {
|
||||
String loginUsingId(Integer userId, String loginUrl, String prv);
|
||||
|
||||
/** subject */
|
||||
private Integer sub;
|
||||
boolean check(String prv);
|
||||
|
||||
/** Issued At */
|
||||
private Long iat;
|
||||
Integer userId();
|
||||
|
||||
/** Expiration Time */
|
||||
private Long exp;
|
||||
void logout();
|
||||
|
||||
/** Not Before */
|
||||
private Long nbf;
|
||||
String jti();
|
||||
|
||||
/** JWT ID */
|
||||
private String jti;
|
||||
Long expired();
|
||||
|
||||
/** Issuer */
|
||||
private String iss;
|
||||
|
||||
/** Payload */
|
||||
private String prv;
|
||||
HashMap<String, String> parse(String token);
|
||||
}
|
@ -15,20 +15,18 @@
|
||||
*/
|
||||
package xyz.playedu.api.service;
|
||||
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface JWTService {
|
||||
JwtToken generate(Integer userId, String iss, String prv);
|
||||
public interface BackendAuthService {
|
||||
String loginUsingId(Integer userId, String loginUrl);
|
||||
|
||||
boolean isInBlack(String jti);
|
||||
boolean check();
|
||||
|
||||
void logout(String token, String prv) throws JwtLogoutException;
|
||||
Integer userId();
|
||||
|
||||
void userLogout(String token) throws JwtLogoutException;
|
||||
void logout();
|
||||
|
||||
void adminUserLogout(String token) throws JwtLogoutException;
|
||||
String jti();
|
||||
|
||||
JWTPayload parse(String token, String prv) throws JwtLogoutException;
|
||||
HashMap<String, String> parse(String token);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2023 杭州白书科技有限公司
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface FrontendAuthService {
|
||||
String loginUsingId(Integer userId, String loginUrl);
|
||||
|
||||
boolean check();
|
||||
|
||||
Integer userId();
|
||||
|
||||
void logout();
|
||||
|
||||
String jti();
|
||||
|
||||
HashMap<String, String> parse(String token);
|
||||
}
|
@ -19,11 +19,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import xyz.playedu.api.domain.UserLoginRecord;
|
||||
|
||||
/**
|
||||
* @author tengteng
|
||||
* @description 针对表【user_login_records】的数据库操作Service
|
||||
* @createDate 2023-03-10 13:40:33
|
||||
*/
|
||||
public interface UserLoginRecordService extends IService<UserLoginRecord> {
|
||||
UserLoginRecord store(
|
||||
Integer userId,
|
||||
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2023 杭州白书科技有限公司
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.SaLoginConfig;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import xyz.playedu.api.config.AuthConfig;
|
||||
import xyz.playedu.api.service.AuthService;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Autowired private AuthConfig authConfig;
|
||||
|
||||
@Override
|
||||
public String loginUsingId(Integer userId, String loginUrl, String prv) {
|
||||
StpUtil.login(
|
||||
userId,
|
||||
SaLoginConfig.setExtra("url", loginUrl)
|
||||
.setExtra("prv", prv)
|
||||
.setExtra(
|
||||
"exp",
|
||||
String.valueOf(
|
||||
System.currentTimeMillis()
|
||||
+ authConfig.getExpired() * 1000L)));
|
||||
return StpUtil.getTokenValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(String prv) {
|
||||
if (!StpUtil.isLogin()) {
|
||||
return false;
|
||||
}
|
||||
String tokenPrv = (String) StpUtil.getExtra("prv");
|
||||
return prv.equals(tokenPrv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer userId() {
|
||||
return StpUtil.getLoginIdAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
StpUtil.logout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jti() {
|
||||
return (String) StpUtil.getExtra("rnStr");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long expired() {
|
||||
return (Long) StpUtil.getExtra("exp");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> parse(String token) {
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("jti", (String) StpUtil.getExtra(token, "rnStr"));
|
||||
data.put("exp", (String) StpUtil.getExtra(token, "exp"));
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2023 杭州白书科技有限公司
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.service.impl;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.service.AuthService;
|
||||
import xyz.playedu.api.service.BackendAuthService;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@Service
|
||||
public class BackendAuthServiceImpl implements BackendAuthService {
|
||||
@Autowired private AuthService authService;
|
||||
|
||||
@Override
|
||||
public String loginUsingId(Integer userId, String loginUrl) {
|
||||
return authService.loginUsingId(userId, loginUrl, SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check() {
|
||||
return authService.check(SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer userId() {
|
||||
return authService.userId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
authService.logout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jti() {
|
||||
return authService.jti();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> parse(String token) {
|
||||
return authService.parse(token);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2023 杭州白书科技有限公司
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.service.impl;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.service.AuthService;
|
||||
import xyz.playedu.api.service.FrontendAuthService;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@Service
|
||||
public class FrontendAuthServiceImpl implements FrontendAuthService {
|
||||
|
||||
@Autowired private AuthService authService;
|
||||
|
||||
@Override
|
||||
public String loginUsingId(Integer userId, String loginUrl) {
|
||||
return authService.loginUsingId(userId, loginUrl, SystemConstant.JWT_PRV_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check() {
|
||||
return authService.check(SystemConstant.JWT_PRV_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer userId() {
|
||||
return authService.userId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
authService.logout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jti() {
|
||||
return authService.jti();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> parse(String token) {
|
||||
return authService.parse(token);
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 杭州白书科技有限公司
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.service.impl;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.JwtBuilder;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.RedisUtil;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class JwtServiceImpl implements JWTService {
|
||||
|
||||
@Value("${playedu.jwt.key}")
|
||||
private String ConfigKey;
|
||||
|
||||
@Value("${playedu.jwt.expire}")
|
||||
private Long ConfigExpire;
|
||||
|
||||
@Value("${playedu.jwt.cache-black-prefix}")
|
||||
private String ConfigCacheBlackPrefix;
|
||||
|
||||
public JwtToken generate(Integer userId, String iss, String prv) {
|
||||
long curTime = System.currentTimeMillis();
|
||||
|
||||
JWTPayload payload = new JWTPayload();
|
||||
payload.setPrv(prv);
|
||||
payload.setIss(iss);
|
||||
payload.setJti(HelperUtil.uuid());
|
||||
payload.setNbf(curTime);
|
||||
payload.setIat(curTime);
|
||||
payload.setExp(curTime + ConfigExpire * 1000);
|
||||
payload.setSub(userId);
|
||||
|
||||
JwtBuilder builder = Jwts.builder();
|
||||
builder.setId(payload.getJti())
|
||||
.setIssuedAt(new Date(payload.getIat()))
|
||||
.claim("prv", payload.getPrv());
|
||||
builder.setExpiration(new Date(payload.getExp())).setIssuer(payload.getIss());
|
||||
builder.setSubject(String.valueOf(payload.getSub()))
|
||||
.setNotBefore(new Date(payload.getNbf()));
|
||||
builder.signWith(getSecretKey());
|
||||
|
||||
JwtToken token = new JwtToken();
|
||||
token.setToken(builder.compact());
|
||||
token.setExpire(payload.getExp() / 1000);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public JWTPayload parse(String token, String prv) throws JwtLogoutException {
|
||||
Claims claims = parseToken(token, prv);
|
||||
JWTPayload payload = new JWTPayload();
|
||||
|
||||
payload.setSub(Integer.valueOf(claims.getSubject()));
|
||||
payload.setIss(claims.getIssuer());
|
||||
payload.setPrv((String) claims.get("prv"));
|
||||
payload.setNbf(claims.getNotBefore().getTime());
|
||||
payload.setExp(claims.getExpiration().getTime());
|
||||
payload.setIat(claims.getIssuedAt().getTime());
|
||||
payload.setJti(claims.getId());
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public boolean isInBlack(String jti) {
|
||||
return RedisUtil.exists(getBlackCacheKey(jti));
|
||||
}
|
||||
|
||||
public void logout(String token, String prv) throws JwtLogoutException {
|
||||
Claims claims = parseToken(token, prv);
|
||||
String cacheKey = getBlackCacheKey(claims.getId());
|
||||
Long expire = (claims.getExpiration().getTime() - System.currentTimeMillis()) / 1000;
|
||||
RedisUtil.set(cacheKey, 1, expire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userLogout(String token) throws JwtLogoutException {
|
||||
logout(token, SystemConstant.JWT_PRV_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adminUserLogout(String token) throws JwtLogoutException {
|
||||
logout(token, SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
}
|
||||
|
||||
private Claims parseToken(String token, String prv) throws JwtLogoutException {
|
||||
Claims claims =
|
||||
(Claims)
|
||||
Jwts.parserBuilder()
|
||||
.setSigningKey(getSecretKey())
|
||||
.require("prv", prv)
|
||||
.build()
|
||||
.parse(token)
|
||||
.getBody();
|
||||
if (isInBlack(claims.getId())) {
|
||||
throw new JwtLogoutException();
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
private SecretKey getSecretKey() {
|
||||
return Keys.hmacShaKeyFor(ConfigKey.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private String getBlackCacheKey(String jti) {
|
||||
return ConfigCacheBlackPrefix + jti;
|
||||
}
|
||||
}
|
@ -56,6 +56,14 @@ mybatis-plus:
|
||||
# configuration:
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
sa-token:
|
||||
token-name: "Authorization"
|
||||
timeout: 1296000 #token有效期[单位:秒,默认15天]
|
||||
is-concurrent: false #限制同时登录
|
||||
is-share: false
|
||||
jwt-secret-key: "playeduxyz"
|
||||
token-prefix: "Bearer"
|
||||
|
||||
# PlayEdu
|
||||
playedu:
|
||||
# 图形验证码
|
||||
|
Loading…
x
Reference in New Issue
Block a user