【Spring AI】基于专属知识库的RAG智能问答小程序开发——功能优化:用户鉴权

系列文章目录

  1. 【Spring AI】基于专属知识库的RAG智能问答小程序开发------完整项目(含完整前端+后端代码)
  2. 【Spring AI】基于专属知识库的RAG智能问答小程序开发------代码逐行精讲:核心ChatClient对象相关构造函数
  3. 【Spring AI】基于专属知识库的RAG智能问答小程序开发------代码逐行精讲:核心交互函数及RAG知识库构建
  4. 【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>
相关推荐
爱吃鱼饼的猫7 分钟前
【Spring篇】Spring的生命周期
java·开发语言
程序猿大波16 分钟前
基于Java,SpringBoot和Vue高考志愿填报辅助系统设计
java·vue.js·spring boot
m0_7401546727 分钟前
SpringMVC 请求和响应
java·服务器·前端
技能咖31 分钟前
2025春招市场迎AI热潮:生成式人工智能(GAI)认证如何重构人才竞争力
人工智能
橘猫云计算机设计40 分钟前
基于Java的班级事务管理系统(源码+lw+部署文档+讲解),源码可白嫖!
java·开发语言·数据库·spring boot·微信小程序·小程序·毕业设计
多多*1 小时前
JavaEE企业级开发 延迟双删+版本号机制(乐观锁) 事务保证redis和mysql的数据一致性 示例
java·运维·数据库·redis·mysql·java-ee·wpf
计算机-秋大田1 小时前
基于Spring Boot的个性化商铺系统的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
士别三日&&当刮目相看1 小时前
JAVA学习*String类
java·开发语言·学习
烂蜻蜓1 小时前
深度解读 C 语言运算符:编程运算的核心工具
java·c语言·前端
2301_764441331 小时前
基于BERT的序列到序列(Seq2Seq)模型,生成文本摘要或标题
人工智能·python·深度学习·bert