系列文章目錄
- 【Spring AI】基于專屬知識庫的RAG智能問答小程序開發——完整項目(含完整前端+后端代碼)
- 【Spring AI】基于專屬知識庫的RAG智能問答小程序開發——代碼逐行精講:核心ChatClient對象相關構造函數
- 【Spring AI】基于專屬知識庫的RAG智能問答小程序開發——代碼逐行精講:核心交互函數及RAG知識庫構建
- 【Spring AI】基于專屬知識庫的RAG智能問答小程序開發——功能優化:用戶鑒權主體功能開發
- 【Spring AI】基于專屬知識庫的RAG智能問答小程序開發——功能優化:用戶鑒權相關工具類代碼
文章目錄
- 系列文章目錄
- 前言
- 1.開發工具及環境準備
- 1.1.開發工具
- 1.2.數據庫準備
- 1.2.1.數據表構建命令
- 1.2.2.數據表構建效果
- 2.后端代碼-登錄鑒權
- 2.1.SpringBoot文件架構:
- 2.2.SpringBoot核心文件代碼:
- 2.2.1.UserController代碼:主要用于定義Controller層邏輯,接收和返回網絡請求
- 2.2.2.UserService代碼:主要用于定義Service層接口
- 2.2.3.UserServiceImpl代碼:主要用于定義Service層的具體邏輯實現
- 2.2.4.UserMapper代碼:主要用于定義Mapper層的接口以及具體實現
前言
在前幾篇文章中,我們不僅成功搭建了一個具備知識檢索與生成能力的AI問答系統,實現了從知識庫構建、向量化存儲到微信端交互的完整鏈路。還通過代碼逐行精講闡明了后端開發中SpringAI框架的使用方法和相關參數含義。
顯而易見地,一個成熟的AI問答助手需要對用戶鑒權,從而保證用戶身份的真實性和請求的合法性。通過對用戶鑒權我們就能夠限定用戶發送的請求數,從而避免api的惡意攻擊和消耗。因此,本文主要通過編寫后端中的SpringBoot代碼實現用戶鑒權邏輯,前端則主要使用wx.login函數獲取用戶的code后進一步獲取openid,最終實現身份認證。
1.開發工具及環境準備
1.1.開發工具
IntelliJ IDEA
微信開發者工具
MySQL
JDK版本 >= 17
Spring Boot版本 >= 3.3.x
阿里云百煉api_keyu獲取:阿里云百煉官網api獲取教程
1.2.數據庫準備
1.2.1.數據表構建命令
CREATE TABLE user (id INT AUTO_INCREMENT PRIMARY KEY,openid VARCHAR(50) NOT NULL UNIQUE,res_request INT NOT NULL DEFAULT 5
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1.2.2.數據表構建效果
2.后端代碼-登錄鑒權
2.1.SpringBoot文件架構:
2.2.SpringBoot核心文件代碼:
2.2.1.UserController代碼:主要用于定義Controller層邏輯,接收和返回網絡請求
package com.alichat.alibabaChatModel.controller;import com.alichat.alibabaChatModel.DTO.UserLoginDTO;
import com.alichat.alibabaChatModel.VO.UserLoginVO;
import com.alichat.alibabaChatModel.constant.JwtClaimsConstant;
import com.alichat.alibabaChatModel.entity.User;
import com.alichat.alibabaChatModel.properties.JwtProperties;
import com.alichat.alibabaChatModel.result.Result;
import com.alichat.alibabaChatModel.service.UserService;
import com.alichat.alibabaChatModel.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;/*** 用戶管理*/@RestController
@RequestMapping("/ali/user")
@Slf4j
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JwtProperties jwtProperties;/*** 微信登錄* @param userLoginDTO* @return*/@PostMapping("/login")public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {log.info("微信登錄:{}", userLoginDTO.getCode());User user = userService.wxlogin(userLoginDTO);HashMap<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.USER_ID, user.getId());String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);UserLoginVO userLoginVO = UserLoginVO.builder().id(user.getId()).openid(user.getOpenid()).token(token).build();log.info(userLoginVO.getToken());return Result.success(userLoginVO);}}
2.2.2.UserService代碼:主要用于定義Service層接口
package com.alichat.alibabaChatModel.service;import com.alichat.alibabaChatModel.DTO.UserLoginDTO;
import com.alichat.alibabaChatModel.entity.User;public interface UserService {/*** 微信登錄* @param userLoginDTO* @return*/User wxlogin(UserLoginDTO userLoginDTO);/*** 根據用戶id查詢用戶* @param id* @return*/User getById(Long id);/*** 更新用戶* @param user* @return*/void updateUser(User user);
}
2.2.3.UserServiceImpl代碼:主要用于定義Service層的具體邏輯實現
package com.alichat.alibabaChatModel.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alichat.alibabaChatModel.DTO.UserLoginDTO;
import com.alichat.alibabaChatModel.constant.MessageConstant;
import com.alichat.alibabaChatModel.entity.User;
import com.alichat.alibabaChatModel.exception.AccountNotFoundException;
import com.alichat.alibabaChatModel.exception.LoginFailedException;
import com.alichat.alibabaChatModel.exception.PasswordErrorException;
import com.alichat.alibabaChatModel.mapper.UserMapper;
import com.alichat.alibabaChatModel.properties.WeChatProperties;
import com.alichat.alibabaChatModel.service.UserService;
import com.alichat.alibabaChatModel.utils.HttpClientUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;@Service
public class UserServiceImpl implements UserService {//微信服務接口地址public static final String WX_LOGIN = "http://api.weixin.qq.com/sns/jscode2session";@Autowiredprivate WeChatProperties weChatProperties;@AutowiredUserMapper userMapper;/*** 調用微信接口服務,獲取微信用戶的openid* @param code* @return*/private String getOpenid(String code) {Map<String, String> map = new HashMap<String, String>();map.put("appid", weChatProperties.getAppid());map.put("secret", weChatProperties.getSecret());map.put("js_code", code);map.put("grant_type", "authorization_code");String json = HttpClientUtil.doGet(WX_LOGIN, map);JSONObject jsonObject = JSON.parseObject(json);String openid = jsonObject.getString("openid");return openid;}/*** 微信登錄* @param userLoginDTO* @return*/public User wxlogin(UserLoginDTO userLoginDTO) {String openid = getOpenid(userLoginDTO.getCode());if(openid == null) {throw new LoginFailedException(MessageConstant.LOGIN_FAILED);}User user = userMapper.getByOpenid(openid);long resRequset = 5;if(user == null) {user = User.builder().openid(openid).resRequest(resRequset).build();userMapper.insert(user);}return user;}/*** 根據用戶id查詢用戶* @param id* @return*/public User getById(Long id){User user = userMapper.getById(id);return user;}/*** 更新用戶* @param user* @return*/public void updateUser(User user){userMapper.update(user);}
}
2.2.4.UserMapper代碼:主要用于定義Mapper層的接口以及具體實現
代碼主要分為兩個同名文件,java文件位于com.alichat.alibabaChatModel的mapper文件夾下,xml文件位于resources的mapper文件夾下,這兩個文件時對應的。
UserMapper.java文件代碼:
package com.alichat.alibabaChatModel.mapper;import com.alichat.alibabaChatModel.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface UserMapper {/*** 根據openid獲取用戶* @param openid* @return*/@Select("select * from user where openid = #{openid}")User getByOpenid(String openid);/*** 插入用戶* @param user*/void insert(User user);/*** 根據id獲取用戶* @param id* @return*/@Select("select * from user where id = #{id}")User getById(Long id);/*** 更新用戶* @param user* @return*/void update(User user);
}
UserMapper.xml文件代碼:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.alichat.alibabaChatModel.mapper.UserMapper"><insert id="insert" useGeneratedKeys="true" keyProperty="id">insert into user (openid, res_request)values (#{openid},#{resRequest})</insert><update id="update">update user<set><if test="openid != null">openid = #{openid},</if><if test="resRequest != null">res_request = #{resRequest},</if></set>where id = #{id}</update>
</mapper>