浏览代码

Merge branch 'cuidi1'

cuidi 1 年之前
父节点
当前提交
7b10a657c8

+ 72 - 0
controller/src/main/java/com/koobietech/eas/controller/StudentLoginController.java

@@ -0,0 +1,72 @@
+package com.koobietech.eas.controller;
+
+import com.anji.captcha.model.common.ResponseModel;
+import com.anji.captcha.model.vo.CaptchaVO;
+import com.anji.captcha.service.CaptchaService;
+import com.koobietech.eas.common.exception.EasException;
+import com.koobietech.eas.common.result.JsonResult;
+import com.koobietech.eas.dao.Pojo.AdminPojo;
+import com.koobietech.eas.dao.adminLoginPojo.UserDetail;
+import com.koobietech.eas.dao.dto.LoginToken;
+import com.koobietech.eas.service.StudentLoginService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+@RestController
+@Tag(name = "学生登陆模块")
+public class StudentLoginController {
+
+    @Resource
+    CaptchaService captchaService;
+
+    @Resource
+    StudentLoginService studentLoginService;
+
+    @PostMapping("/studentLogin")
+    @Operation(summary = "学生登陆", description = "用户名和密码为请求载荷,若登录成功,返回两个token")
+    public JsonResult studentLogin(@RequestBody AdminPojo adminPojo) {
+
+        CaptchaVO captchaVO = new CaptchaVO();
+        captchaVO.setCaptchaVerification(adminPojo.getCaptchaVerification());
+
+        ResponseModel response = captchaService.verification(captchaVO);
+        if (!response.isSuccess()) {
+            throw new EasException(response.getRepMsg(), Integer.parseInt(response.getRepCode()));
+        }
+
+        LoginToken ret = studentLoginService.studentLogin(adminPojo);
+        return JsonResult.data(ret);
+    }
+
+    @GetMapping("/getStudentInfo")
+    @Operation(summary = "获取学生信息", description = "根据Token获取学生信息")
+    public JsonResult getStudentInfo(@RequestHeader("Authorization") String token) {
+        UserDetail ret = studentLoginService.getStudentInfo(token);
+        return JsonResult.data(ret);
+    }
+
+    @PostMapping("/studentRefreshToken")
+    @Operation(summary = "刷新token", description = "当token过期,在请求头中携带refresh token,若刷新成功,返回新的token和refresh token")
+    public JsonResult refreshToken(@RequestHeader("AUthorization") String refreshToken) {
+        LoginToken ret = studentLoginService.refreshToken(refreshToken);
+        return JsonResult.data(ret);
+    }
+
+    @PostMapping("/studentVerifyGet")
+    @Operation(summary = "获取验证码", description = "前端发起获取验证码请求,后端访问静态资源返回滑动图片")
+    public JsonResult verifyGet(@RequestBody CaptchaVO captchaVO) {
+        JsonResult ret = studentLoginService.verifyToJsonResult(captchaService.get(captchaVO));
+        return JsonResult.data(ret);
+    }
+
+    @PostMapping("/studentVerifyCheck")
+    @Operation(summary = "核对验证码轨迹", description = "前端把用户的滑动轨迹转化成字符串传入后端,通过算法判断轨迹是否为真人")
+    public JsonResult verifyCheck(@RequestBody CaptchaVO captchaVO) {
+        JsonResult ret = studentLoginService.verifyToJsonResult(captchaService.check(captchaVO));
+        return JsonResult.data(ret);
+    }
+
+}

+ 1 - 1
controller/src/main/resources/application-local.yaml

@@ -4,7 +4,7 @@ spring:
   datasource:
     url: jdbc:mysql://127.0.0.1:3306/eas?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=true&tinyInt1isBit=false
     username: root
-    password: 123456
+    password: 1234
     driver-class-name: com.mysql.cj.jdbc.Driver
   redis:
     host: localhost

+ 4 - 0
dao/src/main/java/com/koobietech/eas/dao/mapper/AdminLoginMapper.java

@@ -13,6 +13,10 @@ public interface AdminLoginMapper {
 
     UserDetail getUserDetailById(Long adminId);
 
+    List<Permission> getStudentPermissionsById(Long adminId);
 
+    List<Department> getStudentDepartmentsById(Long adminId);
+
+    UserDetail getStudentDetailById(Long adminId);
 
 }

+ 59 - 0
dao/src/main/resources/com/koobietech/eas/dao/mapper/AdminLoginMapper.xml

@@ -33,6 +33,37 @@
         <result column="email" property="email"/>
     </resultMap>
 
+    <resultMap id="permissionResult" type="com.koobietech.eas.dao.adminLoginPojo.Permission">
+        <!-- 映射查询结果到实体类属性 -->
+        <id column="id" property="id"/>
+        <result column="name" property="name"/>
+        <result column="is_active" property="isActive"/>
+        <result column="create_time" property="createTime"/>
+        <result column="modify_time" property="modifyTime"/>
+        <result column="create_uid" property="createUid"/>
+        <result column="description" property="description"/>
+    </resultMap>
+
+    <resultMap id="departmentResult" type="com.koobietech.eas.dao.adminLoginPojo.Department">
+        <!-- 映射查询结果到实体类属性 -->
+        <id column="id" property="id"/>
+        <result column="depname" property="depname"/>
+        <result column="address" property="address"/>
+        <result column="phone" property="phone"/>
+        <result column="email" property="email"/>
+        <result column="manager" property="manager"/>
+        <result column="create_time" property="createTime"/>
+        <result column="modify_time" property="modifyTime"/>
+        <result column="create_uid" property="createUid"/>
+    </resultMap>
+
+    <resultMap id="studentDetailResult" type="com.koobietech.eas.dao.adminLoginPojo.UserDetail">
+        <!-- 映射查询结果到实体类属性 -->
+        <result column="id" property="id"/>
+        <result column="student_name" property="username"/>
+        <result column="phone" property="phone"/>
+        <result column="email" property="email"/>
+    </resultMap>
 
 
 
@@ -81,4 +112,32 @@
         WHERE id = #{adminId}
     </select>
 
+    <select id="getStudentDetailById" resultMap="studentDetailResult">
+        SELECT
+            id,
+            student_name,
+            phone,
+            email
+        FROM
+            eas_sys_student
+        WHERE
+            id = #{adminId}
+    </select>
+
+    <select id="getStudentPermissionsById" resultMap="permissionResult">
+        SELECT p.id, p.name, p.is_active, p.create_time, p.modify_time, p.create_uid, p.description
+        FROM eas_sys_student s
+                 JOIN eas_sys_pes_relation pr ON s.id = pr.department_id
+                 JOIN eas_sys_permission p ON pr.permission_id = p.id
+        WHERE s.id = #{adminId};
+    </select>
+
+    <select id="getStudentDepartmentsById" resultMap="departmentResult">
+        SELECT DISTINCT d.id, d.depname, d.address, d.phone, d.email, d.manager, d.create_time, d.modify_time, d.create_uid
+        FROM eas_sys_student s
+                 JOIN eas_sys_pes_relation pr ON s.id = pr.department_id
+                 JOIN eas_sys_department d ON pr.department_id = d.id
+        WHERE s.id = #{adminId}
+    </select>
+
 </mapper>

+ 82 - 0
security/src/main/java/com/koobietech/eas/security/filter/EasStudentFilter.java

@@ -0,0 +1,82 @@
+package com.koobietech.eas.security.filter;
+
+import com.koobietech.eas.common.exception.EasException;
+import com.koobietech.eas.common.pojo.JwtUserDto;
+import com.koobietech.eas.common.utils.JwtManager;
+import com.koobietech.eas.dao.adminLoginPojo.Permission;
+import com.koobietech.eas.dao.adminLoginPojo.UserDetail;
+import com.koobietech.eas.service.StudentLoginRedisService;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.Resource;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+public class EasStudentFilter extends OncePerRequestFilter {
+
+    @Resource
+    private StudentLoginRedisService studentLoginRedisService;
+
+    @Resource
+    JwtManager jwtManager;
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+
+        //从请求里面拿到token
+        String token = request.getHeader("Authorization");
+        //判断token是否存在
+        if (StringUtils.hasText(token)) {
+            //解析token成JwtUserDto
+            JwtUserDto jwtUserDto = null;
+            try {
+                //过滤器 允许 Token 不正确, 后面Security 会拦截处理
+                jwtUserDto = jwtManager.decodeJwt(token);
+            } catch ( EasException e) {}
+            if ( Objects.nonNull(jwtUserDto) ) {
+                //判断token是否有效
+                UserDetail userDetail = studentLoginRedisService.checkToken(jwtUserDto);
+
+                // 获取当前的 SecurityContext 对象,用于保存当前用户的安全上下文信息
+                SecurityContext context = SecurityContextHolder.getContext();
+
+                // 如果获取到了有效的用户对象
+                if (Objects.nonNull(userDetail)) {
+
+                    // 获取用户的权限列表
+                    List<Permission> permissions = userDetail.getPermissions();
+                    // 创建一个 ArrayList 集合,用于存储用户权限对应的 SimpleGrantedAuthority 权限对象
+                    ArrayList<SimpleGrantedAuthority> objects = new ArrayList<>();
+
+                    // 遍历学生的权限
+                    for (Permission studentPermission : permissions) {
+                        // 创建一个 SimpleGrantedAuthority 权限对象,并添加到集合中
+                        SimpleGrantedAuthority authority = new SimpleGrantedAuthority(studentPermission.getDescription());
+                        objects.add(authority);
+                    }
+
+                    // 使用用户的用户名、空凭证参数和权限对象集合创建一个 UsernamePasswordAuthenticationToken 身份验证令牌
+                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetail.getUsername(), null, objects);
+
+                    // 将身份验证令牌设置到当前的 SecurityContext 中
+                    context.setAuthentication(authenticationToken);
+                }
+            }
+        }
+        filterChain.doFilter(request, response);
+    }
+
+}

+ 19 - 0
service/src/main/java/com/koobietech/eas/service/StudentLoginRedisService.java

@@ -0,0 +1,19 @@
+package com.koobietech.eas.service;
+
+import com.koobietech.eas.common.pojo.JwtUserDto;
+import com.koobietech.eas.dao.adminLoginPojo.UserDetail;
+
+public interface StudentLoginRedisService {
+
+    String createJwtTokenKey(JwtUserDto jwtUserDto);
+
+    String createJwtRefreshTokenKey(JwtUserDto jwtUserDto);
+
+    void loginSavaCache(String redisTokenKey, UserDetail userDetail, Integer token_expires);
+
+    UserDetail loginGetCache(String newRedisTokenKey);
+
+    UserDetail checkToken(JwtUserDto jwtUserDto);
+
+    Boolean loginDeleteCache(String newRedisRefreshTokenKey);
+}

+ 19 - 0
service/src/main/java/com/koobietech/eas/service/StudentLoginService.java

@@ -0,0 +1,19 @@
+package com.koobietech.eas.service;
+
+import com.anji.captcha.model.common.ResponseModel;
+import com.koobietech.eas.common.result.JsonResult;
+import com.koobietech.eas.dao.Pojo.AdminPojo;
+import com.koobietech.eas.dao.adminLoginPojo.UserDetail;
+import com.koobietech.eas.dao.dto.LoginToken;
+
+
+public interface StudentLoginService {
+    LoginToken studentLogin(AdminPojo adminPojo);
+
+    LoginToken refreshToken(String refreshToken);
+
+    //将ResponseModel返回值类型转成JsonResult返回类型
+    JsonResult verifyToJsonResult(ResponseModel response);
+
+    UserDetail getStudentInfo(String token);
+}

+ 57 - 0
service/src/main/java/com/koobietech/eas/service/impl/StudentLoginRedisServiceImpl.java

@@ -0,0 +1,57 @@
+package com.koobietech.eas.service.impl;
+
+import com.koobietech.eas.common.exception.EasException;
+import com.koobietech.eas.common.pojo.JwtUserDto;
+import com.koobietech.eas.common.service.RedisService;
+import com.koobietech.eas.dao.adminLoginPojo.UserDetail;
+import com.koobietech.eas.service.StudentLoginRedisService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+@Service
+public class StudentLoginRedisServiceImpl implements StudentLoginRedisService {
+
+    @Resource
+    RedisService redisService;
+
+
+    @Override
+    public UserDetail checkToken(JwtUserDto jwtUserDto) {
+        String jwtKey = createJwtTokenKey(jwtUserDto);
+        //判断redis里面是否有这个key
+        if (!redisService.hasKey(jwtKey)) {
+            throw new EasException("token已过期");
+        }
+        return (UserDetail) redisService.get(jwtKey);
+    }
+
+    @Override
+    public Boolean loginDeleteCache(String newRedisRefreshTokenKey) {
+        return redisService.del(newRedisRefreshTokenKey);
+    }
+
+    public String createJwtTokenKey(JwtUserDto jwtUserDto) {
+        //根据jwtUserDto 生成jwtKey,格式为:eas_token_{id}_{username}_{type}
+        return "eas_token" + "_" + jwtUserDto.getId() + "_" + jwtUserDto.getUsername() + "_" + jwtUserDto.getType();
+    }
+
+    public String createJwtRefreshTokenKey(JwtUserDto jwtUserDto) {
+        //根据jwtUserDto 生成jwtKey,格式为:eas_refresh_{id}_{username}_{type}
+        return "eas_refresh" + "_" + jwtUserDto.getId() + "_" + jwtUserDto.getUsername() + "_" + jwtUserDto.getType();
+    }
+
+    public void loginSavaCache(String redisTokenKey, UserDetail userDetail, Integer token_expires) {
+        redisService.set(redisTokenKey, userDetail, token_expires);
+    }
+
+    public UserDetail loginGetCache(String newRedisTokenKey) {
+        //看看redis里面有没有这个key
+        if (redisService.hasKey(newRedisTokenKey)) {
+            //有的话,就从redis里面取出来
+            return (UserDetail) redisService.get(newRedisTokenKey);
+        }
+        return null;
+    }
+
+}

+ 188 - 0
service/src/main/java/com/koobietech/eas/service/impl/StudentLoginServiceImpl.java

@@ -0,0 +1,188 @@
+package com.koobietech.eas.service.impl;
+
+import com.anji.captcha.model.common.ResponseModel;
+import com.koobietech.eas.common.constant.UserType;
+import com.koobietech.eas.common.exception.EasException;
+import com.koobietech.eas.common.pojo.JwtUserDto;
+import com.koobietech.eas.common.result.JsonResult;
+import com.koobietech.eas.common.utils.JwtManager;
+import com.koobietech.eas.common.utils.PasswordManager;
+import com.koobietech.eas.dao.Pojo.AdminPojo;
+import com.koobietech.eas.dao.adminLoginPojo.UserDetail;
+import com.koobietech.eas.dao.dto.LoginToken;
+import com.koobietech.eas.dao.mapper.AdminLoginMapper;
+import com.koobietech.eas.mbg.mapper.EasSysStudentMapper;
+import com.koobietech.eas.mbg.model.EasSysStudent;
+import com.koobietech.eas.mbg.model.EasSysStudentExample;
+import com.koobietech.eas.service.StudentLoginRedisService;
+import com.koobietech.eas.service.StudentLoginService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class StudentLoginServiceImpl implements StudentLoginService {
+
+
+    @Resource
+    EasSysStudentMapper easSysStudentMapper;
+
+    @Resource
+    PasswordManager passwordManager;
+
+    @Resource
+    PasswordEncoder passwordEncoder;
+
+    @Resource
+    AdminLoginMapper adminLoginMapper;
+
+    @Resource
+    StudentLoginRedisService studentLoginRedisService;
+
+    @Resource
+    JwtManager jwtManager;
+
+    // token过期时间 单位:s
+    private final Integer token_expires = 60 * 3;
+
+    private final Integer refreshToken_expires = 60 * 7;
+
+    @Override
+    public LoginToken studentLogin(AdminPojo adminPojo) {
+        if (adminPojo.getUsername() == null || adminPojo.getPasswd() == null || adminPojo.getUsername().equals("") || adminPojo.getPasswd().equals("")) {
+            throw new EasException("用户不存在", 412);
+        }
+        EasSysStudent easSysStudent = findStudentByUsername(adminPojo.getUsername(), adminPojo.getPasswd());
+
+        // 接收到对象,根据这个信息去查询数据库,然后自定义sql查用户信息,存在redis里面当做token
+        System.out.println(easSysStudent);
+
+        Long adminId = easSysStudent.getId();
+
+        //先调用自定义sql查询detail类中的数据 最后把这个类封装到redis里面
+        UserDetail userDetail = adminLoginMapper.getStudentDetailById(adminId);
+        System.out.println("接收前" + userDetail);
+        userDetail.setDepartments(adminLoginMapper.getStudentDepartmentsById(adminId));
+        userDetail.setPermissions(adminLoginMapper.getStudentPermissionsById(adminId));
+        System.out.println("接收后" + userDetail);
+
+        // 先调用自定义sql查询学生详细信息、部门信息 和 权限信息
+        UserType student = UserType.MEMBER;
+
+        // 生成token
+        JwtUserDto jwtUserDto = new JwtUserDto(userDetail.getUsername(), userDetail.getId(), student);
+
+        String token = jwtManager.createJwt(jwtUserDto, token_expires);
+
+        String refreshToken = jwtManager.createJwt(jwtUserDto, refreshToken_expires);
+
+        System.out.println("token" + token);
+
+        System.out.println("refreshToken" + refreshToken);
+
+        // 生成redis key
+        String jwtTokenKey = studentLoginRedisService.createJwtTokenKey(jwtUserDto);
+
+        String jwtRefreshTokenKey = studentLoginRedisService.createJwtRefreshTokenKey(jwtUserDto);
+
+        // 将token存入redis
+        studentLoginRedisService.loginSavaCache(jwtTokenKey, userDetail, token_expires);
+
+        studentLoginRedisService.loginSavaCache(jwtRefreshTokenKey, userDetail, refreshToken_expires);
+
+        // 登录成功
+        return new LoginToken(token, refreshToken);
+    }
+
+    @Override
+    public LoginToken refreshToken(String refreshToken) {
+        // 解析refresh token
+        JwtUserDto jwtUserDto = jwtManager.decodeJwt(refreshToken);
+
+        //生成新的 刷新k值 (refresh_token)
+        String newRedisRefreshTokenKey = studentLoginRedisService.createJwtRefreshTokenKey(jwtUserDto);
+
+        //查询redis里面有没有这个k值
+        UserDetail userDetail = studentLoginRedisService.loginGetCache(newRedisRefreshTokenKey);
+
+        if (userDetail == null) {
+            throw new EasException("token已过期", 412);
+        }
+
+        //如果不为空 那UserDetail里面就封装了用户的信息 生成新的token和refresh token
+        String newToken = jwtManager.createJwt(jwtUserDto, token_expires);
+        String newRefreshToken = jwtManager.createJwt(jwtUserDto, refreshToken_expires);
+
+        //生成新的k值 (token)
+        String newRedisTokenKey = studentLoginRedisService.createJwtTokenKey(jwtUserDto);
+
+        // 更新Redis中的token和refresh token
+        studentLoginRedisService.loginSavaCache(newRedisTokenKey, userDetail, token_expires);
+        studentLoginRedisService.loginSavaCache(newRedisRefreshTokenKey, userDetail, refreshToken_expires);
+        return new LoginToken(newToken, newRefreshToken);
+    }
+
+    @Override
+    public JsonResult verifyToJsonResult(ResponseModel response) {
+        JsonResult result = new JsonResult();
+
+        if (response != null) {
+            result.setMsg(response.getRepMsg());
+            result.setCode(Integer.parseInt(response.getRepCode()));
+            result.setStatus(response.isSuccess());
+            result.setData(response.getRepData());
+        } else {
+            throw new EasException("ResponseModel参数为空", 9000);
+        }
+
+        return result;
+    }
+
+    @Override
+    public UserDetail getStudentInfo(String token) {
+
+        try {
+            // 解析token
+            JwtUserDto jwtUserDto = jwtManager.decodeJwt(token);
+            // 封装成字符以便在redis中查找
+            String jwtTokenKey = studentLoginRedisService.createJwtTokenKey(jwtUserDto);
+            UserDetail userDetail = studentLoginRedisService.loginGetCache(jwtTokenKey);
+            return userDetail;
+        } catch (EasException e) {
+            throw new EasException("Token获取学生信息失败", e);
+        }
+
+    }
+
+    private EasSysStudent findStudentByUsername(String username, String password) {
+        EasSysStudentExample easSysStudentExample = new EasSysStudentExample();
+        easSysStudentExample.createCriteria().andStudentNameEqualTo(username);
+        List<EasSysStudent> studentList = easSysStudentMapper.selectByExample(easSysStudentExample);
+        // 使用Optional简化判断
+        Optional<EasSysStudent> optionalStudent = studentList.stream().findFirst();
+
+        if (optionalStudent.isEmpty()) {
+            throw new EasException("用户不存在", 9902);
+        }
+        if (studentList.size() > 1) {
+            throw new EasException("用户数据异常", 9902);
+        }
+
+        EasSysStudent easSysStudent = optionalStudent.get();
+        // 验证密码 这个方法里面有解密 如果解密失败会抛出异常
+        validatePassword(password, easSysStudent.getPasswd());
+        return easSysStudent;
+    }
+
+    private void validatePassword(String inputPassword, String encryptedPassword) {
+        String decryptedPassword = passwordManager.decryptPassword(inputPassword);
+        System.out.println("aes解密密码decryptedPassword: " + decryptedPassword);
+        System.out.println("数据库里的加密密码easSysUserinfo.getPasswd(): " + encryptedPassword);
+        if (!passwordEncoder.matches(decryptedPassword, encryptedPassword)) {
+            throw new EasException("密码不正确", 9901);
+        }
+    }
+}