目录
一、基于用户的内存认证
@Configuration
//@EnableWebSecurity //开启springSecurity自定义配置(springboot默认开启)
public class MySecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
//创建基于内存的用户信息管理器
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//创建UserDetails对象,用于管理用户名,密码,角色,权限等
manager.createUser(User.withDefaultPasswordEncoder().username("user").password("123456").roles("USER").build());
return manager;
}
}
二、基于数据库用户认证
2.1、添加数据库
#创建数据库
CREATE DATABASE `security-demo`;
#创建表
CREATE TABLE `user`(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) DEFAULT NULL,
`password` VARCHAR(400) DEFAULT NULL,
`enabled` BOOLEAN NOT NULL
);
#添加唯一索引
CREATE UNIQUE INDEX `user_name_uindex` ON `user`(`name`);
#添加数据
INSERT INTO `user`(`name`,`password`,`enabled`) VALUES('admin','{bcrypt}$2a$10$FGfmxDS7Vr/xdE4bheKgFOPZjjxn74r7GV17qR0mkG9PZCT/MmmfO',TRUE),
('jack','{bcrypt}$2a$10$FGfmxDS7Vr/xdE4bheKgFOPZjjxn74r7GV17qR0mkG9PZCT/MmmfO',TRUE),
('tom','{bcrypt}$2a$10$FGfmxDS7Vr/xdE4bheKgFOPZjjxn74r7GV17qR0mkG9PZCT/MmmfO',TRUE);
2.2、添加相关pom依赖
这里要将版本统一否则运行报错
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4.1</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
springboot配置文件
#数据库
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security-demo
spring.datasource.username=root
spring.datasource.password=123456
#sql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2.3、测试实现
实现步骤:
1、创建一个DBUserDetailsManagerConfig 类实现UserDetailsManager, UserDetailsPasswordService 接口
2、实现loadUserByUsername()方法
测试代码:
@Data
public class User {
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
private String name;
private String password;
private Boolean enabled;
}
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
<?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.cjc.securitydemo.mapper.UserMapper">
</mapper>
public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@GetMapping("/getListUser")
public List<User> getListUser(){
return userService.list();
}
}
方式一:使用@Component
@Component
public class DBUserDetailsManagerConfig implements UserDetailsManager, UserDetailsPasswordService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("name",username);
User user = userMapper.selectOne(userQueryWrapper);
if (user == null) {
throw new UsernameNotFoundException(username);
}else {
Collection<GrantedAuthority> collection = Arrays.asList();
return new org.springframework.security.core.userdetails.User(
user.getName(),
user.getPassword(),
user.getEnabled(),
true,//用户账号是否过期
true, //用户凭证是否过期
true, //用户是否被锁定
collection //权限列表
);
}
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
return null;
}
@Override
public void createUser(UserDetails user) {
}
@Override
public void updateUser(UserDetails user) {
}
@Override
public void deleteUser(String username) {
}
@Override
public void changePassword(String oldPassword, String newPassword) {
}
@Override
public boolean userExists(String username) {
return false;
}
方式二: 不使用@Component
@Bean
public UserDetailsService dbUserDetailsManagerConfig(){
return new DBUserDetailsManagerConfig();
}
三、添加用户
添加该依赖用于测试
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
void saveUser(User user);
@Autowired
private DBUserDetailsManagerConfig dbUserDetailsManagerConfig;
@Override
public void saveUser(User user) {
dbUserDetailsManagerConfig.createUser(org.springframework.security.core.userdetails.User
.withDefaultPasswordEncoder()
.username(user.getName())
.password(user.getPassword())
.build());
}
@Component
public class DBUserDetailsManagerConfig implements UserDetailsManager, UserDetailsPasswordService {
@Autowired
private UserMapper userMapper;
//添加用户信息
@Override
public void createUser(UserDetails user) {
User myUser = new User();
myUser.setName(user.getUsername());
myUser.setPassword(user.getPassword());
myUser.setEnabled(true);
userMapper.insert(myUser);
}
}
@PostMapping("/addUser")
public void addUser(@RequestBody User user){
userService.saveUser(user);
System.out.println("添加一次");
}
四、密码加密
@Test
void contextLoads() {
//工作因子,默认为10,最小4,最大31,防止密码被暴力破解
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(4);
String encode = bCryptPasswordEncoder.encode("123456");
System.out.println(encode);
if (bCryptPasswordEncoder.matches("123456", encode)){
System.out.println("密码正确");
}else {
System.out.println("密码错误");
}
}
五、 自定义登录页
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests(
authorize -> authorize
.anyRequest() //对所有请求开启授权保护
.authenticated() //已认证的请求会自动授权
)
.formLogin(
//Customizer.withDefaults()
form -> form.loginPage("/login")
.permitAll()//无需授权就能访问
.usernameParameter("name")
.passwordParameter("pass")
);//使用表单授权方式
//.httpBasic(Customizer.withDefaults());//使用基本授权方式
httpSecurity.csrf(csrf -> csrf.disable());//关闭csrf功能
return httpSecurity.build();
}
@Controller
public class LoginController {
@GetMapping("/login")
public String getLogin(){
return "login";
}
}
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>登录</title>
</head>
<body>
<h1>登录</h1>
<div th:if="${param.error}">
错误的用户名或密码
</div>
<form th:action="@{/login}" method="post">
<div>
<input type="text" name="name" placeholder="用户名"/>
</div>
<div>
<input type="password" name="pass" placeholder="密码"/>
</div>
<input type="submit" value="登录"/>
</form>
</body>
</html>