微服务项目->在线oj系统(Java-Spring)----4.0
·

加密算法
加密算法是⼀种将明⽂转换为密⽂的过程,以保护数据的安全性和机密性
作用
安全性:
存储明⽂密码是⾮常不安全的。如果数据库被⾮法访问或泄露,攻击者可以直接获取所有⽤⼾的密码。减少内部⻛险:即使企业内有不诚实的员⼯或管理员,他们也⽆法轻易获取其他管理员的密码,因为密码是加密存储的提升⽤⼾信任度密码加密有助于提升⽤⼾对⽹站或应⽤程序的信任感,使其更愿意使⽤加密保护的⽹站。
常⻅的加密算法
可逆算法:⼀种可以将加密后的密⽂还原为原始明⽂的算法。
不可逆算法:⼀种⽆法将加密后的密⽂还原为原始明⽂的算法

BCrypt
Bcrypt是⼀种哈希加密算法,被⼴泛应⽤于存储密码和进⾏⾝份验证。
Bcrypt算法在计算时会先⽣成⼀个随机的盐值与⽤⼾密
码⼀起参与计算最终得到⼀个加密后的字符串。由于⽣成的盐值是随机的,所以即使每次使⽤相同的 密码得到结果也是不同的。这样可以有效的防⽌攻击者使⽤⼀些⼿段破解⽤⼾密码。
使用
提供加密算法⼯具类
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 加密算法工具类
*/
public class BCryptUtils {
/**
* 生成加密后密文
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后密文
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
}
具体服务中应用
1.先将我们进行加密后的密码存入数据库
2.在服务中需要进行比较的地方,使用matchPassword方法
if(BCryptUtils.matchesPassword(password,sysUser.getPassword())){
loginResult.setCode(ResultCode.SUCCESS.getCode());
loginResult.setMsg(ResultCode.SUCCESS.getMsg());
return loginResult;
}
代码优化
之前写的代码太过于冗余,样式相同的代码需要重复书写,这样以后有需求改动的时候,需要修改的地方过多,这里进行了代码的优化
package com.bite.common.core.domain;
import com.bite.common.core.enums.ResultCode;
import lombok.Data;
@Data
public class R <T>{
private T data;
private String msg;
private int code;
public static <T> R<T> ok() {
return assembleResult(null, ResultCode.SUCCESS);
}
public static <T> R<T> ok(T data) {
return assembleResult(data, ResultCode.SUCCESS);
}
public static <T> R<T> fail() {
return assembleResult(null, ResultCode.FAILED);
}
public static <T> R<T> fail(int code, String msg) {
return assembleResult(code, msg, null);
}
public static <T> R<T> fail(ResultCode resultCode) {
return assembleResult(null, resultCode);
}
private static <T> R<T> assembleResult(T data, ResultCode resultCode) {
R<T> r = new R<>();
r.setCode(resultCode.getCode());
r.setData(data);
r.setMsg(resultCode.getMsg());
return r;
}
private static <T> R<T> assembleResult(int code, String msg, T data) {
R<T> r = new R<>();
r.setCode(code);
r.setData(data);
r.setMsg(msg);
return r;
}
}
@Service
public class SysUserServiceImp implements ISysUserService{
@Autowired
private SysUserMapper sysUserMapper;
@Override
public R<Void> login(String userAccount, String password) {
LambdaQueryWrapper<SysUser> queryWrapper=new LambdaQueryWrapper<>();
SysUser sysUser= sysUserMapper.selectOne(queryWrapper.select(SysUser::getPassword).eq(SysUser::getUserAccount,userAccount));
if(sysUser==null){
return R.fail(ResultCode.FAILED_USER_NOT_EXISTS);
}
if(BCryptUtils.matchesPassword(password,sysUser.getPassword())){
return R.ok();
}
return R.fail(ResultCode.FAILED_LOGIN);
}
}
全局异常处理
使用全局异常处理的原因
- 统一管理异常,避免程序崩溃
当程序运行中出现未捕获的异常(如空指针、文件读取失败等),若没有全局处理机制,程序会直接崩溃并抛出错误信息。全局异常处理可捕获这些异常,避免系统突然终止。
- 提升用户体验,隐藏技术细节
- 集中记录日志,便于问题追踪
- 减少代码冗余,提高开发效率
1.在oj-common下,创建oj-common-security⼦⼯程

2.引入依赖
<dependencies>
<dependency>
<groupId>com.bite</groupId>
<artifactId>oj-common-core</artifactId>
<version>${oj-common-core.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3.创建GlobalExceptionHandler类
package com.bite.common.security;
import com.bite.common.core.domain.R;
import com.bite.common.core.enums.ResultCode;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 请求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return R.fail(ResultCode.ERROR);
}
/**
* 拦截运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生运行时异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
/**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public R<?> handleException(Exception e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
}
@RestControllerAdvice:当抛出异常时, @RestControllerAdvice 标注的类将被⾃动调⽤,
并根据异常类型和处理程序的注解来决定如何处理该异常。这使得开发者可以在整个应⽤程序范围内统⼀处理异常。
@ExceptionHandler: @ExceptionHandler⼀般与@RestControllerAdvice配合使⽤,使⽤其来捕获和处理不同类型的异常。
4.创建org.springframework.boot.autoconfigure.AutoConfiguration.imports⽂件

com.bite.common.security.GlobalExceptionHandler
5.具体服务引入依赖
<dependency>
<groupId>com.bite</groupId>
<artifactId>oj-common-security</artifactId>
<version>${oj-common-security.version}</version>
</dependency>
⽇志框架引⼊
为了更加方便我们进行代码错误的定位,我们这里需要引入日志框架
这里选择slf4j+logback

为什么选择slf4j+logback

主要原因:配置灵活,springBoot的默认日志框架
配置⽂件
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/oj-system" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 10天 -->
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 10天 -->
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--日志级别-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="console" />
<appender-ref ref="file_error" />
</root>
</configuration>
详细内容解释
配置日志的存放路径


日志输出格式



控制台路径输出格式

文件名字以及日志文件存放路径

滚动策略


最大文件存在时间

日志格式

过滤级别(接受日志级别)

日志级别配置

注意:日志只能接受比比日志级别高的日志
eg:定义为info时候可以接受到比它级别高的error日志,但是定义为error时候不能接受带info级别日志
测试使用
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 请求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return R.fail(ResultCode.ERROR);
}
/**
* 拦截运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生运行时异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
/**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public R<?> handleException(Exception e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
}
更多推荐



所有评论(0)