springboot實現(xiàn)注冊加密與登錄解密功能(demo)
前情提要:本demo是基于springboot+mybatis-plus實現(xiàn)加密,加密為主,全局異常處理,日志處理為輔,而登錄密碼加密是每個項目中必須要的,密碼不可能明文存入數據,這樣沒有安全性。
涉及的功能,全局異常處理,日志處理,mybatis-plus實現(xiàn)與數據庫的交互,密碼加密,restful風格
涉及的工具:IDEA,postman,sqlyog(navicat)
1. 首先我們直接看效果吧,如果你不滿意,也就沒必要看了


如果這正是你想要的效果呢,那你可以繼續(xù)看下面的內容了
2. 首先,我們看下pom.xml文件
以下依賴為所需的主要依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.jgsu</groupId> <artifactId>springboot_rsa_encryption</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot_encryption</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- WEB依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 熱部署依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- mysql的依賴,用于連接數據庫--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- lombok依賴,簡化set/get方法 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> </dependency> <!--druid數據源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <!--spring-security實現(xiàn)密碼加密--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.1.6.RELEASE</version> </dependency> <!--fastjsoon--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.51</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3. 創(chuàng)建啟動類SpringbootEncryptionApplication
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@SpringBootApplication
@MapperScan("com.jgsu.mapper")
public class SpringbootEncryptionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootEncryptionApplication.class, args);
}
/**
* 將加密工具類加入IOC容器中,便于加密
* */
@Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
4.實體類
這里只有用戶名和密碼(其他數據自己可擴展)
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
@TableId(value = "id",type = IdType.AUTO)
private int id;
private String username;
private String password;
}
5. service層(業(yè)務層)
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jgsu.entity.User;
import com.jgsu.exception.DataAddException;
import com.jgsu.exception.DataMatchException;
import com.jgsu.mapper.UserMapper;
import com.jgsu.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
// 數據加密,在啟動類中已經注入進IOC容器中
@Autowired
private BCryptPasswordEncoder encoder;
@Override
public User userLogin(String username,String password) {
// mybatis-plus的條件構造器,這里實現(xiàn)根據username查詢
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.eq("username", username);
User userLogin = userMapper.selectOne(wrapper);
/**
* encoder.matches(password, userLogin.getPassword(),實現(xiàn)輸入的密碼與數據庫中的密碼進
* 行匹配,如果匹配成功則返回匹配的數據給controller層,如果失敗則拋異常。
* 為什么沒鹽,沒有解密了?因為這個已經被CryptPasswordEncoder封裝好了,
* 在encoder.matches()方進行解密匹配完全幫你封裝好了,所以不必考慮,
* 只需要將前端傳入的密碼與數據庫中加密后的密碼進行匹配就行。
* **/
if (userLogin != null && encoder.matches(password, userLogin.getPassword())) {
log.info("用戶{},登錄成功",username);
return userLogin;
} else {
log.error("用戶名或密碼錯誤");
throw new DataMatchException("405", "用戶名或密碼錯誤");
}
}
@Override
public User userRegister(String username, String password) {
User user = new User();
user.setId(user.getId());
user.setUsername(username);
user.setPassword(encoder.encode(password));
int i = userMapper.insert(user);
if (i == 1){
log.info("用戶{}注冊成功",username);
return user;
}else {
log.error("服務器發(fā)生異常,注冊失敗");
throw new DataAddException("403","注冊失敗");
}
}
}
6. mapper層
如果不了解,可以建議去看看mybatis-plus官方文檔
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jgsu.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
}
7.controller層
import com.jgsu.entity.User;
import com.jgsu.service.UserService;
import com.jgsu.utils.CommonResult;
import com.jgsu.utils.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
// 注冊,基于restful風格
@GetMapping("/register/{username}/{password}")
public CommonResult register(@PathVariable("username") String username,@PathVariable("password") String password){
User user = userService.userRegister(username, password);
if (user != null){
return CommonResult.success(ResultCode.SUCCESS);
}else {
return CommonResult.failed(ResultCode.FAILED);
}
}
// 登錄,基于restful風格
@GetMapping("/login/{username}/{password}")
public CommonResult login(@PathVariable("username") String username,@PathVariable("password") String password) {
User userLogin = userService.userLogin(username,password);
if (userLogin != null) {
return CommonResult.success(ResultCode.SUCCESS);
} else {
return CommonResult.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR);
}
}
}
8.配置類(返回json數據的類)
封裝錯誤碼的接口
public interface IErrorCode {
long getState();
String getMessage();
}
枚舉了一些常用API操作碼
public enum ResultCode implements IErrorCode {
/**
* 成功
*/
SUCCESS(200, "ok"),
/**
* 失敗
*/
FAILED(500, "server error"),
/**
* 驗證過期
*/
VALIDATE_FAILED(404, "undefined"),
/**
* 未登錄
*/
UNAUTHORIZED(401, "未登錄"),
/**
* 用戶名或密碼錯誤
*/
USERNAME_OR_PASSWORD_ERROR(405, "用戶名或密碼錯誤"),
/**
* 數據查詢錯誤
*/
DATA_Not_Exist_ERROR(603, "數據不存在"),
/**
* 數據添加出現(xiàn)問題
*/
DATA_ADD_ERROR(604, "數據添加異常"),
/**
* 文件
*/
FILE_ERROR(605, "上傳文件出現(xiàn)錯誤"),
/**
* 數據查詢出現(xiàn)問題
*/
IMAGE_ERROR(606, "圖片處理出現(xiàn)錯誤"),
/**
* 權限不夠
*/
FORBIDDEN(403, "forbidden");
private long state;
private String stateInfo;
ResultCode(long state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
@Override
public long getState() {
return state;
}
@Override
public String getMessage() {
return stateInfo;
}
}
通用返回對象
public class CommonResult<T> {
private long state;
private String stateInfo;
private T data;
public CommonResult() {
}
public CommonResult(long state, String stateInfo, T data) {
this.state = state;
this.stateInfo = stateInfo;
this.data = data;
}
public CommonResult(long state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
/**
* 成功返回結果
*
* @param data 獲取的數據
*/
public static <T> CommonResult<T> success(T data) {
return new CommonResult<T>(ResultCode.SUCCESS.getState(), ResultCode.SUCCESS.getMessage(), data);
}
/**
* 成功返回結果
* @param data 獲取的數據
* @param message 提示信息
* @return
*/
public static <T> CommonResult<T> success(T data, String message) {
return new CommonResult<T>(ResultCode.SUCCESS.getState(), message, data);
}
/**
* 失敗返回結果
* @param errorCode 錯誤碼
*/
public static <T> CommonResult<T> failed(IErrorCode errorCode) {
return new CommonResult<T>(errorCode.getState(), errorCode.getMessage(), null);
}
/**
* 失敗返回結果
* @param message 提示信息
*/
public static <T> CommonResult<T> failed(String message) {
return new CommonResult<T>(ResultCode.FAILED.getState(), message, null);
}
/**
* 失敗返回結果
* @param code
* @param message
*/
public static <T> CommonResult<T> failed(int code, String message) {
return failed(ResultCode.FAILED);
}
/**
* 參數驗證失敗返回結果
*/
public static <T> CommonResult<T> validateFailed() {
return failed(ResultCode.VALIDATE_FAILED);
}
/**
* 參數驗證失敗返回結果
* @param message 提示信息
*/
public static <T> CommonResult<T> validateFailed(String message) {
return new CommonResult<T>(ResultCode.VALIDATE_FAILED.getState(), message, null);
}
/**
* 未登錄返回結果
*/
public static <T> CommonResult<T> unauthorized(T data) {
return new CommonResult<T>(ResultCode.UNAUTHORIZED.getState(), ResultCode.UNAUTHORIZED.getMessage(), data);
}
/**
* 未授權返回結果
*/
public static <T> CommonResult<T> forbidden(T data) {
return new CommonResult<T>(ResultCode.FORBIDDEN.getState(), ResultCode.FORBIDDEN.getMessage(), data);
}
public long getState() {
return state;
}
public void setState(long state) {
this.state = state;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
9. 異常類
全局異常攔截類
@Slf4j
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHander {
@ExceptionHandler(value = Exception.class)
public CommonResult handlerException(Exception e){
if (e instanceof DataAddException){
log.error("【全局異常攔截】DataAddException: 請求方法 {}, 請求路徑 {}",((DataAddException)e).getCode(),((DataAddException)e).getMessage());
return CommonResult.failed(ResultCode.DATA_ADD_ERROR);
}else if (e instanceof DataMatchException){
log.error("【全局異常攔截】DataMatchException: 請求方法 {}, 請求路徑 {}",((DataMatchException)e).getCode(),((DataMatchException)e).getMessage());
return CommonResult.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR);
} else {
log.error("服務器內部出錯{}",e);
return CommonResult.failed(ResultCode.FAILED);
}
}
}
自定義數據添加異常類
public class DataAddException extends RuntimeException {
private String code;
private String message;
public DataAddException(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
自定義數據匹配異常類
public class DataMatchException extends RuntimeException {
private String code;
private String message;
public DataMatchException(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
以上是實現(xiàn)該功能的所有類,當然進行密碼加密處理的類只涉及service層以及啟動類,其他類為基本類,如果你只想了解怎么進行加密處理存入數據庫以及怎么登陸就看看service層就行。
總結
到此這篇關于springboot實現(xiàn)注冊的加密與登錄的解密功能的文章就介紹到這了,更多相關springboot實現(xiàn)注冊的加密與登錄的解密內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java classloader和namespace詳細介紹
這篇文章主要介紹了Java classloader和namespace詳細介紹的相關資料,需要的朋友可以參考下2017-03-03
使用spring+maven不同環(huán)境讀取配置方式
這篇文章主要介紹了使用spring+maven不同環(huán)境讀取配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08

