加入验证码登录逻辑
parent
360722a915
commit
485024c88e
37
pom.xml
37
pom.xml
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<swagger.version>2.8.0</swagger.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
|
@ -61,15 +62,43 @@
|
|||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-security</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.zhangmeng</groupId>
|
||||
<artifactId>jwt-security-spring-boot-starter</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>2.0.52</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-bean-validators</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package com.zhangmeng.online.exam.config;
|
||||
|
||||
import com.zhangmeng.jwt.config.SecurityAuthenticationSuccessHandler;
|
||||
import com.zhangmeng.jwt.dto.LoginUser;
|
||||
import com.zhangmeng.jwt.dto.Token;
|
||||
import com.zhangmeng.jwt.response.Result;
|
||||
import com.zhangmeng.jwt.response.StatusCode;
|
||||
import com.zhangmeng.jwt.service.TokenService;
|
||||
import com.zhangmeng.jwt.util.ResponseUtil;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:36
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Component
|
||||
public class LoginSysLog extends SecurityAuthenticationSuccessHandler {
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||
Token token = tokenService.saveToken(loginUser);
|
||||
String message = "登录成功";
|
||||
ResponseUtil.responseJson(response, HttpStatus.OK.value(), new Result(true, StatusCode.OK,message, token));
|
||||
}
|
||||
}
|
||||
|
|
@ -714,4 +714,203 @@ public class InitController {
|
|||
role.getPermissions().add(permission2);
|
||||
roleDao.save(role);
|
||||
}
|
||||
|
||||
@GetMapping("/test4")
|
||||
public void test4() {
|
||||
Subject subject = this.subjectDao.findByCode("001");
|
||||
|
||||
Question question = new Question();
|
||||
question.setSubject(subject);
|
||||
question.setType(Question.Type.JUDGMENT);
|
||||
question.setName("JavaFX 是 Oracle 官方提供的 GUI 框架吗?");
|
||||
this.questionDao.save(question);
|
||||
|
||||
QuestionOption optionA = new QuestionOption();
|
||||
optionA.setQuestion(question);
|
||||
optionA.setOptionName("A.");
|
||||
optionA.setOptionContent("正确");
|
||||
optionA.setOptionOrder(1);
|
||||
optionA.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionA);
|
||||
|
||||
QuestionOption optionB = new QuestionOption();
|
||||
optionB.setQuestion(question);
|
||||
optionB.setOptionName("B.");
|
||||
optionB.setOptionContent("错误");
|
||||
optionB.setOptionOrder(2);
|
||||
optionB.setIsAnswer(false);
|
||||
this.questionOptionDao.save(optionB);
|
||||
|
||||
question.setOptions(Arrays.asList(optionA, optionB));
|
||||
|
||||
question = new Question();
|
||||
question.setSubject(subject);
|
||||
question.setType(Question.Type.JUDGMENT);
|
||||
question.setName("“精兵简政”指精简机构以提高效率,减轻负担。");
|
||||
this.questionDao.save(question);
|
||||
|
||||
optionA = new QuestionOption();
|
||||
optionA.setQuestion(question);
|
||||
optionA.setOptionName("A.");
|
||||
optionA.setOptionContent("正确");
|
||||
optionA.setOptionOrder(1);
|
||||
optionA.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionA);
|
||||
|
||||
optionB = new QuestionOption();
|
||||
optionB.setQuestion(question);
|
||||
optionB.setOptionName("B.");
|
||||
optionB.setOptionContent("错误");
|
||||
optionB.setOptionOrder(2);
|
||||
optionB.setIsAnswer(false);
|
||||
this.questionOptionDao.save(optionB);
|
||||
|
||||
question.setOptions(Arrays.asList(optionA, optionB));
|
||||
|
||||
|
||||
question = new Question();
|
||||
question.setSubject(subject);
|
||||
question.setType(Question.Type.JUDGMENT);
|
||||
question.setName("“知之为知之,不知为不知,是知也”出自《论语》,与孟子无关。");
|
||||
this.questionDao.save(question);
|
||||
|
||||
optionA = new QuestionOption();
|
||||
optionA.setQuestion(question);
|
||||
optionA.setOptionName("A.");
|
||||
optionA.setOptionContent("正确");
|
||||
optionA.setOptionOrder(1);
|
||||
optionA.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionA);
|
||||
|
||||
optionB = new QuestionOption();
|
||||
optionB.setQuestion(question);
|
||||
optionB.setOptionName("B.");
|
||||
optionB.setOptionContent("错误");
|
||||
optionB.setOptionOrder(2);
|
||||
optionB.setIsAnswer(false);
|
||||
this.questionOptionDao.save(optionB);
|
||||
|
||||
question.setOptions(Arrays.asList(optionA, optionB));
|
||||
|
||||
/**
|
||||
* 成语“玲珑剔透”可形容器物精致,也可比喻人精明灵活。
|
||||
*/
|
||||
question = new Question();
|
||||
question.setSubject(subject);
|
||||
question.setType(Question.Type.JUDGMENT);
|
||||
question.setName("“玲珑剔透”可形容器物精致,也可比喻人精明灵活。");
|
||||
question.setExplanation("仅用于器物");
|
||||
this.questionDao.save(question);
|
||||
|
||||
optionA = new QuestionOption();
|
||||
optionA.setQuestion(question);
|
||||
optionA.setOptionName("A.");
|
||||
optionA.setOptionContent("正确");
|
||||
optionA.setOptionOrder(1);
|
||||
optionA.setIsAnswer(false);
|
||||
this.questionOptionDao.save(optionA);
|
||||
|
||||
optionB = new QuestionOption();
|
||||
optionB.setQuestion(question);
|
||||
optionB.setOptionName("B.");
|
||||
optionB.setOptionContent("错误");
|
||||
optionB.setOptionOrder(2);
|
||||
optionB.setIsAnswer(false);
|
||||
this.questionOptionDao.save(optionB);
|
||||
|
||||
question.setOptions(Arrays.asList(optionA, optionB));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* currentQuestion.content = "简述面向对象编程的三大特性";
|
||||
* currentQuestion.keywords = Arrays.asList("封装", "继承", "多态");
|
||||
*/
|
||||
@GetMapping("/test5")
|
||||
public void test6() {
|
||||
Subject subject = this.subjectDao.findByCode("001");
|
||||
|
||||
Question question = new Question();
|
||||
question.setSubject(subject);
|
||||
question.setType(Question.Type.SHORT_ANSWER);
|
||||
question.setName("简述面向对象编程的三大特性");
|
||||
this.questionDao.save(question);
|
||||
|
||||
QuestionOption optionA = new QuestionOption();
|
||||
optionA.setQuestion(question);
|
||||
optionA.setOptionName("A.");
|
||||
optionA.setOptionContent("封装");
|
||||
optionA.setOptionOrder(1);
|
||||
optionA.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionA);
|
||||
|
||||
QuestionOption optionB = new QuestionOption();
|
||||
optionB.setQuestion(question);
|
||||
optionB.setOptionName("B.");
|
||||
optionB.setOptionContent("继承");
|
||||
optionB.setOptionOrder(2);
|
||||
optionB.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionB);
|
||||
|
||||
QuestionOption optionC = new QuestionOption();
|
||||
optionC.setQuestion(question);
|
||||
optionC.setOptionName("B.");
|
||||
optionC.setOptionContent("多态");
|
||||
optionC.setOptionOrder(3);
|
||||
optionC.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionC);
|
||||
|
||||
question.setOptions(Arrays.asList(optionA, optionB, optionC));
|
||||
|
||||
question = new Question();
|
||||
question.setSubject(subject);
|
||||
question.setType(Question.Type.SHORT_ANSWER);
|
||||
question.setName("《朝花夕拾》中鲁迅回忆藤野先生的目的是什么?");
|
||||
this.questionDao.save(question);
|
||||
|
||||
optionA = new QuestionOption();
|
||||
optionA.setQuestion(question);
|
||||
optionA.setOptionName("A.");
|
||||
optionA.setOptionContent("汲取精神力量");
|
||||
optionA.setOptionOrder(1);
|
||||
optionA.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionA);
|
||||
|
||||
optionB = new QuestionOption();
|
||||
optionB.setQuestion(question);
|
||||
optionB.setOptionName("B.");
|
||||
optionB.setOptionContent("封建势力");
|
||||
optionB.setOptionOrder(2);
|
||||
optionB.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionB);
|
||||
|
||||
optionC = new QuestionOption();
|
||||
optionC.setQuestion(question);
|
||||
optionC.setOptionName("C.");
|
||||
optionC.setOptionContent("虚伪");
|
||||
optionC.setOptionOrder(3);
|
||||
optionC.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionC);
|
||||
|
||||
QuestionOption optionD = new QuestionOption();
|
||||
optionD.setQuestion(question);
|
||||
optionD.setOptionName("D.");
|
||||
optionD.setOptionContent("正人君子");
|
||||
optionD.setOptionOrder(4);
|
||||
optionD.setIsAnswer(true);
|
||||
this.questionOptionDao.save(optionD);
|
||||
|
||||
question.setOptions(Arrays.asList(optionA, optionB, optionC,optionD));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/test6")
|
||||
public void test7() {
|
||||
Subject subject = this.subjectDao.findByCode("001");
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ public class PaperController {
|
|||
return Result.error("试卷不存在");
|
||||
}
|
||||
Paper paper = paperOptional.get();
|
||||
|
||||
paper.getQuestions().clear();
|
||||
|
||||
for (String questionId : JSONObject.parseArray(ids, String.class)) {
|
||||
Optional<Question> question = this.questionDao.findById(Long.valueOf(questionId));
|
||||
if (question.isPresent()){
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.zhangmeng.online.exam.controller;
|
||||
|
||||
import com.zhangmeng.jwt.factory.VerificationCodeFactory;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:56
|
||||
* @version: 1.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/verificationCode")
|
||||
public class VerificationCodeController {
|
||||
|
||||
@RequestMapping("/generate")
|
||||
public void generate(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
VerificationCodeFactory.getSpecCaptcha().out(response.getOutputStream());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,4 +9,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
|||
* @version: 1.0
|
||||
*/
|
||||
public interface UserDao extends JpaRepository<User, Long> {
|
||||
|
||||
public User findByUsername(String username);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.zhangmeng.online.exam.service;
|
||||
|
||||
import com.zhangmeng.online.exam.entity.Permission;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:43
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface PermissionService {
|
||||
List<Permission> findByUserId(Long id);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.zhangmeng.online.exam.service;
|
||||
|
||||
import com.zhangmeng.online.exam.entity.User;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:43
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface UserService {
|
||||
User loadUserByUsername(String username);
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.zhangmeng.online.exam.service.impl;
|
||||
|
||||
import com.zhangmeng.online.exam.dao.PermissionDao;
|
||||
import com.zhangmeng.online.exam.dao.UserDao;
|
||||
import com.zhangmeng.online.exam.entity.Permission;
|
||||
import com.zhangmeng.online.exam.entity.Role;
|
||||
import com.zhangmeng.online.exam.entity.User;
|
||||
import com.zhangmeng.online.exam.service.PermissionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:43
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class PermissionServiceImpl implements PermissionService {
|
||||
|
||||
@Autowired
|
||||
private PermissionDao permissionDao;
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Permission> findByUserId(Long id) {
|
||||
Optional<User> userOptional = this.userDao.findById(id);
|
||||
if (userOptional.isPresent()) {
|
||||
User user = userOptional.get();
|
||||
List<Permission> permissions = new ArrayList<>();
|
||||
Set<Role> roles = user.getRoles();
|
||||
for (Role role : roles) {
|
||||
Set<Permission> permissions1 = role.getPermissions();
|
||||
permissions.addAll(permissions1);
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.zhangmeng.online.exam.service.impl;
|
||||
|
||||
import com.zhangmeng.jwt.dto.LoginUser;
|
||||
|
||||
import com.zhangmeng.online.exam.entity.Permission;
|
||||
import com.zhangmeng.online.exam.entity.User;
|
||||
import com.zhangmeng.online.exam.service.PermissionService;
|
||||
import com.zhangmeng.online.exam.service.UserService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:42
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Override
|
||||
public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
User user = this.userService.loadUserByUsername(username);
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException("用户未找到");
|
||||
}
|
||||
|
||||
//判断用户状态是否正常
|
||||
if (!user.getDeleteStatus()) {
|
||||
if (user.getStatus().equals(User.Status.LOCKED)) {
|
||||
throw new LockedException("用户被锁定,请联系管理员");
|
||||
}
|
||||
if (user.getStatus().equals(User.Status.DISABLED)) {
|
||||
throw new DisabledException("用户已作废");
|
||||
}
|
||||
}
|
||||
//根据用户查询权限列表
|
||||
List<Permission> permissions = this.permissionService.findByUserId(user.getId());
|
||||
return new LoginUser(user.getId(),username,user.getPassword(),this.convert_permissions(permissions));
|
||||
}
|
||||
|
||||
//转换
|
||||
private List<com.zhangmeng.jwt.dto.Permission> convert_permissions (List<Permission> permissions){
|
||||
return permissions.parallelStream().filter(permission -> !StringUtils.isEmpty(permission.getName()))
|
||||
.map(permission -> {
|
||||
com.zhangmeng.jwt.dto.Permission permission1 = new com.zhangmeng.jwt.dto.Permission();
|
||||
permission1.setTitle(permission.getName());
|
||||
return permission1;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.zhangmeng.online.exam.service.impl;
|
||||
|
||||
import com.zhangmeng.online.exam.dao.UserDao;
|
||||
import com.zhangmeng.online.exam.entity.User;
|
||||
import com.zhangmeng.online.exam.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/22 15:43
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
|
||||
@Override
|
||||
public User loadUserByUsername(String username) {
|
||||
return this.userDao.findByUsername(username);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.zhangmeng.online.exam.utils;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* @author zm
|
||||
* @date 2025/3/14 16:36
|
||||
|
|
@ -18,4 +20,9 @@ public class PageUtils {
|
|||
return pageNum;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
String password = encoder.encode("123456");
|
||||
System.out.println(password);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,28 @@ spring:
|
|||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQL5Dialect
|
||||
# format_sql: true
|
||||
freemarker:
|
||||
suffix: .ftl
|
||||
check-template-location: true
|
||||
content-type: text/html
|
||||
charset: UTF-8
|
||||
template-loader-path: classpath:/templates/
|
||||
cache: false
|
||||
enabled: true
|
||||
request-context-attribute: request
|
||||
token:
|
||||
jwt-secret: zhangmeng
|
||||
exper-time: 6000
|
||||
jwt:
|
||||
security:
|
||||
login-page: /login
|
||||
login-url: /login
|
||||
logout-url: logout
|
||||
authentication-entry-point-msg: 请先登录后,在进行访问
|
||||
open-api:
|
||||
- /
|
||||
- /login/**
|
||||
- /system/**
|
||||
- /verificationCode/generate
|
||||
- /css/**
|
||||
- /js/**
|
||||
- /editor/**
|
||||
- /swagger-ui.html
|
||||
- /swagger-ui/**
|
||||
- /swagger-resources/**
|
||||
- /v2/api-docs
|
||||
- /v3/api-docs
|
||||
- /doc.html
|
||||
- /webjars/**
|
||||
- /favicon.ico # ??FAVICON
|
||||
Loading…
Reference in New Issue