Browse Source

添加鉴权, 登录, 自动记录对话

zhenghao 5 months ago
parent
commit
9cbac96ba9

+ 6 - 0
pom.xml

@@ -62,6 +62,12 @@
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
 		</dependency>
+		<!--鉴权-->
+		<dependency>
+			<groupId>cn.dev33</groupId>
+			<artifactId>sa-token-spring-boot3-starter</artifactId>
+			<version>1.38.0</version>
+		</dependency>
 		<!--解决 javax.annotation.meta.When.MAYBE 警告 (莫名其妙的警告)-->
 		<dependency>
 			<groupId>com.google.code.findbugs</groupId>

+ 64 - 22
sql/pg.sql

@@ -1,10 +1,4 @@
-
-
--- public.log_error definition
-
--- Drop table
-
--- DROP TABLE log_error;
+DROP TABLE IF EXISTS log_error;
 
 CREATE TABLE log_error (
     id bigserial PRIMARY KEY, -- 主键
@@ -15,15 +9,15 @@ CREATE TABLE log_error (
     create_time timestamp(0) DEFAULT now() NULL -- 创建时间
 );
 
-COMMENT ON COLUMN public.log_error.id IS '主键';
-COMMENT ON COLUMN public.log_error."exception" IS '异常';
-COMMENT ON COLUMN public.log_error.message IS '异常消息';
-COMMENT ON COLUMN public.log_error.error_info IS '异常详细消息';
-COMMENT ON COLUMN public.log_error.error_stack_trace IS '异常堆栈';
-COMMENT ON COLUMN public.log_error.create_time IS '创建时间';
+COMMENT ON COLUMN log_error.id IS '主键';
+COMMENT ON COLUMN log_error."exception" IS '异常';
+COMMENT ON COLUMN log_error.message IS '异常消息';
+COMMENT ON COLUMN log_error.error_info IS '异常详细消息';
+COMMENT ON COLUMN log_error.error_stack_trace IS '异常堆栈';
+COMMENT ON COLUMN log_error.create_time IS '创建时间';
 
 
-DROP TABLE chat_history;
+DROP TABLE IF EXISTS chat_history;
 CREATE TABLE chat_history (
     id bigserial PRIMARY KEY, -- 主键
     user_id text NULL, -- 用户id
@@ -31,13 +25,61 @@ CREATE TABLE chat_history (
     "chat_A" text NULL, -- chat回答
     create_time timestamp(0) DEFAULT now() NULL, -- 创建时间
     update_time timestamp(0) DEFAULT now() NULL, -- 更改时间
-    is_deleted int4 DEFAULT 0 NULL -- 是否删除
+    is_deleted int2 DEFAULT 0 NULL -- 是否删除
+);
+
+COMMENT ON COLUMN chat_history.id IS '主键';
+COMMENT ON COLUMN chat_history.user_id IS '用户id';
+COMMENT ON COLUMN chat_history."user_Q" IS '用户提问';
+COMMENT ON COLUMN chat_history."chat_A" IS 'chat回答';
+COMMENT ON COLUMN chat_history.create_time IS '创建时间';
+COMMENT ON COLUMN chat_history.update_time IS '更改时间';
+COMMENT ON COLUMN chat_history.is_deleted IS '是否删除';
+
+
+DROP TABLE IF EXISTS user_list;
+CREATE TABLE user_list (
+    id bigserial primary key, -- 主键
+    user_id text not null, -- 用户id
+    user_name text unique, -- 用户名
+    user_password text NULL, -- 密码
+    create_time timestamp(0) DEFAULT now() NULL, -- 创建时间
+    update_time timestamp(0) DEFAULT now() NULL, -- 更新时间
+    is_deleted int2 default 0 NULL -- 是否删除
 );
+COMMENT ON TABLE user_list IS '用户列表';
+
+-- Column comments
+
+COMMENT ON COLUMN user_list.id IS '主键';
+COMMENT ON COLUMN user_list.user_id IS '用户id';
+COMMENT ON COLUMN user_list.user_name IS '用户名';
+COMMENT ON COLUMN user_list.user_password IS '密码';
+COMMENT ON COLUMN user_list.create_time IS '创建时间';
+COMMENT ON COLUMN user_list.update_time IS '更新时间';
+COMMENT ON COLUMN user_list.is_deleted IS '是否删除';
+
+
+-- public.search_api definition
+
+-- Drop table
+
+DROP TABLE IF EXISTS search_api;
+CREATE TABLE search_api (
+    id bigserial primary key, -- 自增主键
+    s_method text DEFAULT 'GET'::text NULL, -- 请求方法
+    s_url text NULL, -- 请求地址
+    s_param text NULL, -- 请求参数
+    s_description text NULL, -- 接口说明
+    s_tsdescription tsvector NULL -- 接口说明的全文检索
+);
+CREATE INDEX ON public.search_api USING gin (s_tsdescription);
+
+-- Column comments
 
-COMMENT ON COLUMN public.chat_history.id IS '主键';
-COMMENT ON COLUMN public.chat_history.user_id IS '用户id';
-COMMENT ON COLUMN public.chat_history."user_Q" IS '用户提问';
-COMMENT ON COLUMN public.chat_history."chat_A" IS 'chat回答';
-COMMENT ON COLUMN public.chat_history.create_time IS '创建时间';
-COMMENT ON COLUMN public.chat_history.update_time IS '更改时间';
-COMMENT ON COLUMN public.chat_history.is_deleted IS '是否删除';
+COMMENT ON COLUMN public.search_api.id IS '自增主键';
+COMMENT ON COLUMN public.search_api.s_method IS '请求方法';
+COMMENT ON COLUMN public.search_api.s_url IS '请求地址';
+COMMENT ON COLUMN public.search_api.s_param IS '请求参数';
+COMMENT ON COLUMN public.search_api.s_description IS '接口说明';
+COMMENT ON COLUMN public.search_api.s_tsdescription IS '接口说明的全文检索';

+ 10 - 1
src/main/java/cn/jlsxwkj/common/R/GlobalRestExceptionHandler.java

@@ -1,5 +1,6 @@
 package cn.jlsxwkj.common.R;
 
+import cn.dev33.satoken.exception.SaTokenException;
 import cn.jlsxwkj.common.utils.Log;
 import cn.jlsxwkj.moudles.logerror.LogError;
 import cn.jlsxwkj.moudles.logerror.LogErrorService;
@@ -9,6 +10,7 @@ import org.springframework.web.ErrorResponse;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 
+import javax.security.auth.login.LoginException;
 import java.util.Arrays;
 
 /**
@@ -29,12 +31,19 @@ public class GlobalRestExceptionHandler {
     public ErrorHandler exception(Exception e) {
         ErrorHandler errorHandler = new ErrorHandler();
         errorHandler.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR.code());
-        errorHandler.setMessage(HttpResponseStatus.INTERNAL_SERVER_ERROR.reasonPhrase());
+        errorHandler.setMessage("未知异常");
         errorHandler.setException(e.getClass().getName());
+        if (e instanceof LoginException) {
+            errorHandler.setMessage(e.getMessage());
+        }
         if (e instanceof ErrorResponse) {
             errorHandler.setStatus(((ErrorResponse)e).getStatusCode().value());
             errorHandler.setMessage(e.getMessage());
         }
+        if (e instanceof SaTokenException) {
+            errorHandler.setStatus(((SaTokenException)e).getCode());
+            errorHandler.setMessage("账户未登录/未注册");
+        }
         LogError errorHandlerToLogError = new LogError().castErrorHandlerToLogError(errorHandler);
         errorHandlerToLogError.setErrorInfo(e.getMessage());
         errorHandlerToLogError.setErrorStackTrace(Arrays.toString(e.getStackTrace()));

+ 1 - 1
src/main/java/cn/jlsxwkj/common/R/ResultResponseHandler.java

@@ -19,7 +19,7 @@ import java.util.Arrays;
  * @Author Joker DJ
  * ControllerAdvice 绑定的Controller包的权限定名 例如:com.dj.Controller
  */
-@ControllerAdvice(basePackages = "cn.jlsxwkj.moudles.ragchat")
+@ControllerAdvice(basePackages = "cn.jlsxwkj.moudles")
 public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
 
     @Override

+ 7 - 11
src/main/java/cn/jlsxwkj/common/config/Consumer.java → src/main/java/cn/jlsxwkj/common/config/SaTokenConfigure.java

@@ -1,7 +1,7 @@
 package cn.jlsxwkj.common.config;
 
-import cn.jlsxwkj.common.interceptor.Login;
-import jakarta.annotation.Resource;
+import cn.dev33.satoken.interceptor.SaInterceptor;
+import cn.dev33.satoken.stp.StpUtil;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -10,20 +10,16 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  * @author zh
  */
 @Configuration
-public class Consumer implements WebMvcConfigurer {
-    @Resource
-    private Login logInterceptor;
+public class SaTokenConfigure implements WebMvcConfigurer {
+
     /**
      * 注册拦截器
      * @param registry 注册
      */
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(logInterceptor)
-        // 拦截
-        .addPathPatterns("/**")
-        // 放行
-        .excludePathPatterns("/login");
-        WebMvcConfigurer.super.addInterceptors(registry);
+        registry.addInterceptor(new SaInterceptor(handler -> StpUtil.checkLogin()))
+                .addPathPatterns("/**")
+                .excludePathPatterns("/user/login", "/user/auth");
     }
 }

+ 0 - 29
src/main/java/cn/jlsxwkj/common/interceptor/Login.java

@@ -1,29 +0,0 @@
-package cn.jlsxwkj.common.interceptor;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.ModelAndView;
-import reactor.util.annotation.Nullable;
-
-/**
- * @author zh
- */
-@Component
-public class Login implements HandlerInterceptor {
-    @Override
-    public boolean preHandle(@Nullable HttpServletRequest request,
-                             @Nullable HttpServletResponse response,
-                             @Nullable Object handler) {
-        assert request != null;
-        return true;
-    }
-
-    @Override
-    public void postHandle(@Nullable HttpServletRequest request,
-                           @Nullable HttpServletResponse response,
-                           @Nullable Object handler,
-                           @Nullable ModelAndView modelAndView) {
-    }
-}

+ 0 - 1
src/main/java/cn/jlsxwkj/common/utils/Log.java

@@ -13,7 +13,6 @@ public class Log {
 
     private static final Map<String, Slf4jLog> CACHE_LOGS = new ConcurrentHashMap<>();
 
-    @SuppressWarnings("unused")
     public static void info(Class<?> clazz, String format, Object... args) {
         Slf4jLog log = getLogObj(clazz);
         log.info(format, args);

+ 5 - 9
src/main/java/cn/jlsxwkj/moudles/chat/ChatController.java

@@ -2,6 +2,7 @@ package cn.jlsxwkj.moudles.chat;
 
 import cn.jlsxwkj.moudles.chathistory.ChatHistory;
 import cn.jlsxwkj.moudles.chathistory.ChatHistoryService;
+import cn.jlsxwkj.moudles.userlist.UserListService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -26,6 +27,8 @@ public class ChatController {
 	private ChatService chatService;
 	@Resource
 	private ChatHistoryService chatHistoryService;
+	@Resource
+	private UserListService userListService;
 
 	@Operation(summary = "上传文档")
 	@PostMapping("/upload")
@@ -43,15 +46,8 @@ public class ChatController {
 
 	@Operation(summary = "获取历史对话")
 	@PostMapping("/getHistory")
-	public List<ChatHistory> selectHistory(
-			@Parameter(name = "userId", description = "用户id") @RequestParam String userId) {
-		return chatHistoryService.selectHistoryByUserId(userId);
-	}
-
-	@Operation(summary = "保存历史对话")
-	@PostMapping("/saveHistory")
-	public String saveHistory() {
-		return chatService.saveDialog();
+	public List<ChatHistory> selectHistory() {
+		return chatHistoryService.selectHistoryByUserId();
 	}
 
 	@Operation(summary = "问答文档流")

+ 23 - 35
src/main/java/cn/jlsxwkj/moudles/chat/ChatService.java

@@ -1,14 +1,17 @@
 package cn.jlsxwkj.moudles.chat;
 
+import cn.dev33.satoken.SaManager;
 import cn.hutool.crypto.digest.MD5;
 import cn.jlsxwkj.common.reader.ParagraphDocReader;
 import cn.jlsxwkj.common.reader.ParagraphTextReader;
 import cn.jlsxwkj.common.utils.Log;
 import cn.jlsxwkj.common.utils.MergeDocuments;
-import cn.jlsxwkj.moudles.chathistory.ChatHistory;
 import cn.jlsxwkj.moudles.chathistory.ChatHistoryService;
 import jakarta.annotation.Resource;
-import org.springframework.ai.chat.messages.*;
+import org.springframework.ai.chat.messages.AssistantMessage;
+import org.springframework.ai.chat.messages.Message;
+import org.springframework.ai.chat.messages.SystemMessage;
+import org.springframework.ai.chat.messages.UserMessage;
 import org.springframework.ai.chat.prompt.Prompt;
 import org.springframework.ai.document.Document;
 import org.springframework.ai.document.DocumentReader;
@@ -50,6 +53,10 @@ public class ChatService {
 	@Resource
 	private ChatHistoryService chatHistoryService;
 	/**
+	 * 单条消息
+	 */
+	private static StringBuffer chatMessage;
+	/**
 	 * md5 校验
 	 */
 	private static final MD5 MD5 = cn.hutool.crypto.digest.MD5.create();
@@ -61,31 +68,6 @@ public class ChatService {
 	 * 用户对话上下文
 	 */
 	private static final List<Message> LIST_MESSAGE = new ArrayList<>();
-	/**
-	 * 单条消息
-	 */
-	private static StringBuffer chatMessage;
-
-	/**
-	 * 保存会话
-	 * @return 保存条数
-	 */
-	@SuppressWarnings("unused")
-	public String saveDialog() {
-		List<ChatHistory> chatHistoryList = new ArrayList<>();
-		List<Message> userMessageList = LIST_MESSAGE.stream().filter(x -> x.getMessageType().equals(MessageType.USER)).toList();
-		List<Message> chatMessageList = LIST_MESSAGE.stream().filter(x -> x.getMessageType().equals(MessageType.ASSISTANT)).toList();
-		for (int i = 0; i < userMessageList.size(); i++) {
-			String userMessage = userMessageList.get(i).getContent();
-			String chatMessage = chatMessageList.get(i).getContent();
-			ChatHistory chatHistory = new ChatHistory();
-			chatHistory.setUserId("test");
-			chatHistory.setUserQ(userMessage);
-			chatHistory.setChatA(chatMessage);
-			chatHistoryList.add(chatHistory);
-		}
-		return chatHistoryService.insertAll(chatHistoryList);
-	}
 
 	/**
 	 * 使用spring ai解析txt文档并保存至 pg
@@ -160,16 +142,15 @@ public class ChatService {
 		return ollamaChatModel.stream(chatPrompt2String).map(
 				response -> {
 					String str = response.getResult().getOutput().getContent();
+					System.out.print(str);
 					chatMessage.append(str);
 					return str.replace(" ", "  ");
 				})
 				.concatWithValues("<{完成}>").onErrorStop()
 				.doOnComplete(() -> {
+					System.out.println();
 					LIST_MESSAGE.add(new AssistantMessage(chatMessage.toString()));
-					LIST_MESSAGE.forEach(x -> Log.info(this.getClass(),
-							"message {} : {}",
-							x.getMessageType(),
-							x.getContent()));
+					saveDialog(message, chatMessage.toString());
 				});
 
 	}
@@ -188,11 +169,9 @@ public class ChatService {
 		String result = ollamaChatModel.call(getChatPrompt2String(message, content))
 				.getResult().getOutput().getContent();
 		chatMessage.append(result);
+		Log.info(this.getClass(),"{} message : {}", "chat", result);
 		LIST_MESSAGE.add(new AssistantMessage(chatMessage.toString()));
-		LIST_MESSAGE.forEach(x -> Log.info(this.getClass(),
-				"message {} : {}",
-				x.getMessageType(),
-				x.getContent()));
+		saveDialog(message, chatMessage.toString());
 		return result;
 	}
 
@@ -204,9 +183,18 @@ public class ChatService {
 	 * @return 			提示词
 	 */
 	private Prompt getChatPrompt2String(String message, String context) {
+		Log.info(this.getClass(),"{} message : {}", "user", message);
 		Prompt prompt = new Prompt(LIST_MESSAGE);
 		LIST_MESSAGE.add(new SystemMessage(context));
 		LIST_MESSAGE.add(new UserMessage(message));
 		return prompt;
 	}
+
+	/**
+	 * 保存会话
+	 */
+	private void saveDialog(String userQ, String chatA) {
+		String userId = SaManager.getStpLogic("").getLoginIdAsString();
+		chatHistoryService.insert(userId, userQ, chatA);
+	}
 }

+ 0 - 2
src/main/java/cn/jlsxwkj/moudles/chathistory/ChatHistory.java

@@ -13,7 +13,5 @@ public class ChatHistory {
   private String userQ;
   private String chatA;
   private java.sql.Timestamp createTime;
-  private java.sql.Timestamp updateTime;
-  private Integer isDeleted;
 
 }

+ 13 - 34
src/main/java/cn/jlsxwkj/moudles/chathistory/ChatHistoryMapper.java

@@ -14,41 +14,20 @@ import java.util.List;
 public interface ChatHistoryMapper {
 
     @Insert("""
-            insert into chat_history(
-                user_id,
-                user_Q,
-                chat_A
-            ) values (
-                #{userId},
-                #{userQ},
-                #{chatA}
-            );
-            """)
-    Integer insert(@Param("userId") String userId,
-                   @Param("userQ") String userQ,
-                   @Param("chatA") String chatA);
-
-    @Insert("""
-            insert into chat_history(
-                user_id,
-                user_Q,
-                chat_A
-            ) values #{items}
-            """)
-    Integer insertAll(@Param("items") String items);
+insert into chat_history(user_id, "user_Q", "chat_A") 
+values (#{userId}, #{userQ}, #{chatA})
+""")
+    void insert(@Param("userId") String userId,
+                @Param("userQ") String userQ,
+                @Param("chatA") String chatA);
 
     @Select("""
-            select 
-                id, user_id, 
-                user_Q,
-                chat_A, 
-                create_time, 
-                update_time, 
-                is_deleted
-            from chat_history
-            where user_id = #{userId}
-            order by create_time desc
-            limit 20
-            """)
+select *
+from chat_history
+where user_id = #{userId}
+and is_deleted = 0
+order by create_time desc
+limit 20
+""")
     List<ChatHistory> selectHistoryByUserId(@Param("userId") String userId);
 }

+ 5 - 22
src/main/java/cn/jlsxwkj/moudles/chathistory/ChatHistoryService.java

@@ -1,5 +1,6 @@
 package cn.jlsxwkj.moudles.chathistory;
 
+import cn.dev33.satoken.SaManager;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 
@@ -14,30 +15,12 @@ public class ChatHistoryService {
     @Resource
     private ChatHistoryMapper chatHistoryMapper;
 
-    @SuppressWarnings("unused")
-    public Integer insert(String userId,
-                         String userQ,
-                         String chatA) {
-        return chatHistoryMapper.insert(userId, userQ, chatA);
+    public void insert(String userId, String userQ, String chatA) {
+        chatHistoryMapper.insert(userId, userQ, chatA);
     }
 
-    public String insertAll(List<ChatHistory> items) {
-        StringBuilder values = new StringBuilder();
-        items.forEach(item -> {
-            values.append(String.format("""
-                            ('{}','{}','{}'),
-                            """,
-                    item.getUserId(),
-                    item.getUserQ(),
-                    item.getChatA()
-            ));
-        });
-        values.deleteCharAt(values.lastIndexOf(","));
-        Integer rows = chatHistoryMapper.insertAll(values.toString());
-        return "插入" + rows + "条";
-    }
-
-    public List<ChatHistory> selectHistoryByUserId(String userId) {
+    public List<ChatHistory> selectHistoryByUserId() {
+        String userId = SaManager.getStpLogic("").getLoginIdAsString();
         return chatHistoryMapper.selectHistoryByUserId(userId);
     }
 }

+ 3 - 12
src/main/java/cn/jlsxwkj/moudles/logerror/LogErrorMapper.java

@@ -15,17 +15,8 @@ public interface LogErrorMapper {
      * @param logError log实体
      */
     @Insert("""
-            insert into log_error(
-                message, 
-                exception, 
-                error_info,
-                error_stack_trace
-            ) values (
-                #{LogError.message}, 
-                #{LogError.exception},
-                #{LogError.errorInfo},
-                #{LogError.errorStackTrace}
-            )
-            """)
+insert into log_error(message, exception, error_info,error_stack_trace) 
+values (#{LogError.message}, #{LogError.exception},#{LogError.errorInfo},#{LogError.errorStackTrace})
+""")
     void insertOne(@Param("LogError") LogError logError);
 }

+ 16 - 0
src/main/java/cn/jlsxwkj/moudles/searchapi/SearchApi.java

@@ -0,0 +1,16 @@
+package cn.jlsxwkj.moudles.searchapi;
+
+import lombok.Data;
+
+/**
+ * @author zh
+ */
+@Data
+public class SearchApi {
+    private Integer id;
+    private String sMethod;
+    private String sUrl;
+    private String sParam;
+    private String sDescription;
+    private String sTsdescription;
+}

+ 14 - 0
src/main/java/cn/jlsxwkj/moudles/userlist/UserList.java

@@ -0,0 +1,14 @@
+package cn.jlsxwkj.moudles.userlist;
+
+import lombok.Data;
+
+/**
+ * @author zh
+ */
+@Data
+public class UserList {
+    private Long id;
+    private String userId;
+    private String userName;
+    private String userPassword;
+}

+ 53 - 0
src/main/java/cn/jlsxwkj/moudles/userlist/UserListController.java

@@ -0,0 +1,53 @@
+package cn.jlsxwkj.moudles.userlist;
+
+import cn.dev33.satoken.stp.StpUtil;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import javax.security.auth.login.AccountException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+/**
+ * @author zh
+ */
+@RestController
+@RequestMapping(("/user/"))
+public class UserListController {
+
+    @Resource
+    private UserListService userListService;
+
+    @PostMapping("/login")
+    public String login(@RequestParam String userName,
+                          @RequestParam String userPassword) throws LoginException {
+        UserList userList = userListService.checkUser(userName, userPassword);
+        if (userList != null) {
+            if (!StpUtil.isLogin()) {
+                String userId = userList.getUserId();
+                StpUtil.login(userId);
+                return "登录成功";
+            }
+            throw new LoginException("请勿重复登录");
+        }
+        throw new FailedLoginException("用户未注册/密码错误");
+    }
+
+    @PostMapping("/auth")
+    public String auth(@RequestParam String userName,
+                        @RequestParam String userPassword) throws AccountException {
+        if (userListService.checkUser(userName, userPassword) != null) {
+            throw new AccountException("用户已注册, 请勿重复注册");
+        }
+        if (userListService.authUser(userName, userPassword) > 0) {
+            return "注册成功";
+        }
+        throw new AccountException("注册失败");
+    }
+
+    @GetMapping("/logout")
+    public String logout() {
+        StpUtil.logout();
+        return "登出成功";
+    }
+}

+ 30 - 0
src/main/java/cn/jlsxwkj/moudles/userlist/UserListMapper.java

@@ -0,0 +1,30 @@
+package cn.jlsxwkj.moudles.userlist;
+
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * @author zh
+ */
+@Mapper
+public interface UserListMapper {
+
+    @Insert("""
+insert into user_list(user_id, user_name, user_password
+) values (#{user.userId}, #{user.userName}, #{user.userPassword})
+""")
+    Integer authUser(@Param("user") UserList user);
+
+    @Select("""
+select * 
+from user_list
+where user_name = #{userName} 
+and user_password = #{userPassword}
+and is_deleted = 0
+limit 1
+""")
+    UserList checkUser(@Param("userName") String userName,
+                       @Param("userPassword") String userPassword);
+}

+ 29 - 0
src/main/java/cn/jlsxwkj/moudles/userlist/UserListService.java

@@ -0,0 +1,29 @@
+package cn.jlsxwkj.moudles.userlist;
+
+import cn.dev33.satoken.secure.SaSecureUtil;
+import cn.hutool.core.lang.Snowflake;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author zh
+ */
+@Service
+public class UserListService {
+
+    @Resource
+    private UserListMapper userListMapper;
+    private final Snowflake snowflake = new Snowflake();
+
+    public Integer authUser(String userName, String password) {
+        UserList userList = new UserList();
+        userList.setUserId(snowflake.nextIdStr());
+        userList.setUserName(userName);
+        userList.setUserPassword(SaSecureUtil.sha512(password));
+        return userListMapper.authUser(userList);
+    }
+
+    public UserList checkUser(String userName, String userPassword) {
+        return userListMapper.checkUser(userName, SaSecureUtil.sha512(userPassword));
+    }
+}

+ 3 - 3
src/main/resources/application-dev.yml

@@ -1,8 +1,8 @@
 spring:
   datasource:
-    url: jdbc:postgresql://118.195.196.59:35432/test
+    url: jdbc:postgresql://localhost:5432/postgres
     username: postgres
-    password: xwkj2022@
+    password: postgres
   ai:
     vectorstore:
       pgvector:
@@ -11,6 +11,6 @@ spring:
     ollama:
       base-url: http://localhost:11434
       chat:
-        model: qwen2:7b
+        model: qwen2:1.5b
       embedding:
         model: mofanke/dmeta-embedding-zh

+ 17 - 1
src/main/resources/application.yml

@@ -36,4 +36,20 @@ logging:
 # mybatis
 mybatis:
   configuration:
-    map-underscore-to-camel-case: true
+    map-underscore-to-camel-case: true
+# sa token 鉴权
+sa-token:
+  # token 名称(同时也是 cookie 名称)
+  token-name: token
+  # token 有效期(单位:秒) 默认30天,-1 代表永久有效
+  timeout: 86400
+  # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
+  active-timeout: -1
+  # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
+  is-concurrent: false
+  # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
+  is-share: true
+  # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
+  token-style: uuid
+  # 是否输出操作日志
+  is-log: true