fix: [新增课程报名情况]
This commit is contained in:
parent
86f1df5e08
commit
541a993cb5
|
@ -0,0 +1,46 @@
|
||||||
|
是的,Spring Security 在每次带有 token 的请求中,确实都会走一遍认证流程,但并不一定每次都“存储”认证信息,具体行为取决于你使用的 token 类型(如 JWT、Session、OAuth2 等)和安全配置。
|
||||||
|
|
||||||
|
一、JWT(常见于无状态登录)
|
||||||
|
如果你使用的是 JWT(JSON Web Token)这种无状态认证机制:
|
||||||
|
|
||||||
|
每次请求都要带上 token(通常放在 Authorization Header 中)
|
||||||
|
|
||||||
|
Spring Security 会通过一个过滤器(如 OncePerRequestFilter)解析这个 token
|
||||||
|
|
||||||
|
验证 token 的有效性(比如签名、过期时间)
|
||||||
|
|
||||||
|
从 token 中解析用户信息(如用户名、角色),然后在当前请求的 SecurityContext 中构建认证对象
|
||||||
|
|
||||||
|
请求处理完后,SecurityContext 是线程局部的,不会跨请求存储,下次请求又要重新走这个流程
|
||||||
|
|
||||||
|
✅ 好处是服务无状态、扩展性强
|
||||||
|
❌ 每次请求都要解析和验证 token,有一定性能开销
|
||||||
|
|
||||||
|
二、Session(默认方式)
|
||||||
|
如果你使用的是 Spring Security 默认的基于 Session 的认证机制:
|
||||||
|
|
||||||
|
登录成功后服务端会生成一个 SessionId,并将其通过 Cookie 返回给客户端
|
||||||
|
|
||||||
|
客户端下次请求自动带上 Cookie
|
||||||
|
|
||||||
|
Spring Security 会通过这个 SessionId 直接从服务端 Session 中获取用户的认证信息
|
||||||
|
|
||||||
|
如果存在有效 Session,就不需要重新认证,不走身份验证流程
|
||||||
|
|
||||||
|
✅ 好处是性能较高
|
||||||
|
❌ 缺点是服务有状态,不利于分布式部署(需共享 Session)
|
||||||
|
|
||||||
|
三、OAuth2 Token(Resource Server 模式)
|
||||||
|
如果你用的是 OAuth2,比如使用 spring-security-oauth2-resource-server:
|
||||||
|
|
||||||
|
每次请求带上 Bearer Token
|
||||||
|
|
||||||
|
Spring Security 会通过配置好的 JwtDecoder 验证 token(或远程调用 introspection endpoint)
|
||||||
|
|
||||||
|
同样会在请求级别构建一次 Authentication 对象,不会存储
|
||||||
|
|
||||||
|
总结
|
||||||
|
场景 每次验证 Token 认证信息是否持久化
|
||||||
|
JWT ✅ 是 ❌ 否,线程局部
|
||||||
|
Session ❌ 否,登录一次 ✅ 是,存储在 Session
|
||||||
|
OAuth2 Resource Server ✅ 是 ❌ 否,线程局部
|
|
@ -7,5 +7,3 @@ courseDetail查询时候加入userId
|
||||||
进度表
|
进度表
|
||||||
|
|
||||||
webChat
|
webChat
|
||||||
|
|
||||||
courseCenter View 里面对于course 新增分类 级别
|
|
|
@ -19,6 +19,8 @@ public class SecurityConstants {
|
||||||
"/bs/user/getPhoneCode",
|
"/bs/user/getPhoneCode",
|
||||||
"/bs/user/verifyFace",
|
"/bs/user/verifyFace",
|
||||||
|
|
||||||
|
"/bs/courses/queryByPage",
|
||||||
|
|
||||||
"/challenge",
|
"/challenge",
|
||||||
"/ws/**",
|
"/ws/**",
|
||||||
"/faceTest", "/compareFaces",
|
"/faceTest", "/compareFaces",
|
||||||
|
@ -26,7 +28,7 @@ public class SecurityConstants {
|
||||||
|
|
||||||
"/exam/api/paper/**",
|
"/exam/api/paper/**",
|
||||||
|
|
||||||
"/bs/courses/**",
|
"/bs/courses/queryByPage",
|
||||||
"/api/common/**", //公共接口
|
"/api/common/**", //公共接口
|
||||||
"/demo/**", // 测试接口
|
"/demo/**", // 测试接口
|
||||||
"/api/products",
|
"/api/products",
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.guwan.backend.mapper;
|
||||||
|
|
||||||
|
import com.guwan.backend.pojo.entity.UserCourseRegistration;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 12455
|
||||||
|
* @description 针对表【user_course_registration】的数据库操作Mapper
|
||||||
|
* @createDate 2025-05-11 19:27:07
|
||||||
|
* @Entity com.guwan.backend.pojo.entity.UserCourseRegistration
|
||||||
|
*/
|
||||||
|
public interface UserCourseRegistrationMapper extends BaseMapper<UserCourseRegistration> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.guwan.backend.pojo.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @TableName user_course_registration
|
||||||
|
*/
|
||||||
|
@TableName(value ="user_course_registration")
|
||||||
|
@Data
|
||||||
|
public class UserCourseRegistration {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private Integer userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private Integer courseId;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.guwan.backend.service;
|
||||||
|
|
||||||
|
import com.guwan.backend.pojo.entity.UserCourseRegistration;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 12455
|
||||||
|
* @description 针对表【user_course_registration】的数据库操作Service
|
||||||
|
* @createDate 2025-05-11 19:27:07
|
||||||
|
*/
|
||||||
|
public interface UserCourseRegistrationService extends IService<UserCourseRegistration> {
|
||||||
|
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import com.guwan.backend.pojo.response.courseDetail.ChapterVO;
|
||||||
import com.guwan.backend.pojo.response.courseDetail.CourseDetailVO;
|
import com.guwan.backend.pojo.response.courseDetail.CourseDetailVO;
|
||||||
import com.guwan.backend.pojo.response.courseDetail.ReviewVO;
|
import com.guwan.backend.pojo.response.courseDetail.ReviewVO;
|
||||||
import com.guwan.backend.service.CourseService;
|
import com.guwan.backend.service.CourseService;
|
||||||
|
import com.guwan.backend.util.SecurityUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -50,11 +51,17 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
||||||
|
|
||||||
private final CourseTypeMapper courseTypeMapper;
|
private final CourseTypeMapper courseTypeMapper;
|
||||||
|
|
||||||
|
private final SecurityUtil securityUtil;
|
||||||
|
|
||||||
|
private final UserCourseRegistrationMapper userCourseRegistrationMapper;
|
||||||
|
|
||||||
private static final Map<String, Integer> courseStudentCounts = new ConcurrentHashMap<>();
|
private static final Map<String, Integer> courseStudentCounts = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CourseDetailVO getCourseDetail(String courseId) {
|
public CourseDetailVO getCourseDetail(String courseId) {
|
||||||
|
|
||||||
|
Long currentUserId = securityUtil.getCurrentUserId();
|
||||||
|
|
||||||
//首选查询course表
|
//首选查询course表
|
||||||
Course course = courseMapper.selectOne(new LambdaQueryWrapper<Course>().eq(Course::getId, courseId));
|
Course course = courseMapper.selectOne(new LambdaQueryWrapper<Course>().eq(Course::getId, courseId));
|
||||||
|
|
||||||
|
@ -130,7 +137,12 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
||||||
|
|
||||||
courseDetailVO.setTotalDuration(totalTimeOfMinute / 60);
|
courseDetailVO.setTotalDuration(totalTimeOfMinute / 60);
|
||||||
|
|
||||||
courseDetailVO.setEnrolled(false);
|
|
||||||
|
UserCourseRegistration userCourseRegistration = userCourseRegistrationMapper.selectOne(new LambdaQueryWrapper<UserCourseRegistration>()
|
||||||
|
.eq(UserCourseRegistration::getCourseId, courseId)
|
||||||
|
.eq(UserCourseRegistration::getUserId, currentUserId));
|
||||||
|
|
||||||
|
courseDetailVO.setEnrolled(userCourseRegistration != null);
|
||||||
|
|
||||||
courseDetailVO.setCoverImg(course.getCoverImg());
|
courseDetailVO.setCoverImg(course.getCoverImg());
|
||||||
List<ChapterVO> chapterVOList = new ArrayList<>();
|
List<ChapterVO> chapterVOList = new ArrayList<>();
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.guwan.backend.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.guwan.backend.mapper.UserCourseRegistrationMapper;
|
||||||
|
import com.guwan.backend.pojo.entity.UserCourseRegistration;
|
||||||
|
import com.guwan.backend.service.UserCourseRegistrationService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 12455
|
||||||
|
* @description 针对表【user_course_registration】的数据库操作Service实现
|
||||||
|
* @createDate 2025-05-11 19:27:07
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class UserCourseRegistrationServiceImpl extends ServiceImpl<UserCourseRegistrationMapper, UserCourseRegistration>
|
||||||
|
implements UserCourseRegistrationService {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?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.guwan.backend.mapper.UserCourseRegistrationMapper">
|
||||||
|
|
||||||
|
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.UserCourseRegistration">
|
||||||
|
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||||
|
<result property="userId" column="user_id" jdbcType="INTEGER"/>
|
||||||
|
<result property="courseId" column="course_id" jdbcType="INTEGER"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
id,user_id,course_id
|
||||||
|
</sql>
|
||||||
|
</mapper>
|
Loading…
Reference in New Issue