系列文章目录
- 【Spring AI】基于专属知识库的RAG智能问答小程序开发------完整项目(含完整前端+后端代码)
- 【Spring AI】基于专属知识库的RAG智能问答小程序开发------代码逐行精讲:核心ChatClient对象相关构造函数
- 【Spring AI】基于专属知识库的RAG智能问答小程序开发------代码逐行精讲:核心交互函数及RAG知识库构建
- 【Spring AI】基于专属知识库的RAG智能问答小程序开发------功能优化:用户鉴权主体功能开发
文章目录
前言
在前几篇文章中,我们不仅成功搭建了一个具备知识检索与生成能力的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.数据表构建命令
sql
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层逻辑,接收和返回网络请求
java
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 {
@Autowired
private UserService userService;
@Autowired
private 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层接口
java
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层的具体逻辑实现
java
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";
@Autowired
private WeChatProperties weChatProperties;
@Autowired
UserMapper 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文件代码:
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
<?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>