编写 Spring Security 权限认证代码,通常需要以下几个方面的工作:
1. 定义用户实体类:创建代表用户的实体类,包含用户的基本信息,如用户名、密码、角色等。
2.编写spring security配置类,继承 WebSecurityConfigurerAdapter 并重写相关方法来定义安全策略,如用户认证方式、授权规则、登录页面等。
3. 实现 UserDetailsService 接口:用于从数据源(如数据库)中获取用户的详细信息,包括权限信息。
4. 数据持久化(如果用户信息存储在数据库中):创建数据访问层(DAO)来与数据库交互,获取和保存用户数据。
5.自定义认证方式(如果需要):例如基于令牌(Token)的认证、OAuth 认证等。
6.异常处理:处理在认证和授权过程中可能出现的异常情况,提供友好的错误响应。
7. 前端集成:与前端页面进行交互,处理登录、注销等操作的请求和响应。
8.权限管理相关的服务类和方法:用于更复杂的权限控制逻辑。
9. 测试用例:编写单元测试和集成测试,确保权限认证功能的正确性和稳定性
以下是逐步为您展示上述提到的各个部分的代码示例:
1. 定义用户实体类:
import lombok.Data;
@Data
public class User {
private Long id;
private String username;
private String password;
private String role;
}
2. 实现 UserDetailsService 接口:
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
public class CustomUserDetailsService implements UserDetailsService {
// 假设从数据库或其他数据源获取用户信息
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 模拟查找用户
if ("admin".equals(username)) {
return new org.springframework.security.core.userdetails.User("admin", "$2a$10$o29U7Lz7B77X8uXc837cGee9ZcG63WJ6G9S545UcBq", new ArrayList<>());
} else if ("user".equals(username)) {
return new org.springframework.security.core.userdetails.User("user", "$2a$10$77aB7u3567E9o4c87b8dJukcB67aD5c78o678797b", new ArrayList<>());
}
throw new UsernameNotFoundException("User not found");
}
}
3. 数据持久化(假设使用简单的数据库操作):
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
// 模拟从数据库获取用户数据的方法
public User getUserByUsername(String username) {
// 实际应连接数据库进行查询
if ("admin".equals(username)) {
return new User(1L, "admin", "$2a$10$o29U7Lz7B77X8uXc837cGee9ZcG63WJ6G9S545UcBq", "ADMIN");
} else if ("user".equals(username)) {
return new User(2L, "user", "$2a$10$77aB7u3567E9o4c87b8dJukcB67aD5c78o678797b", "USER");
}
return null;
}
}
4. Spring Security 配置类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private UserRepository userRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
5. 异常处理(示例):
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class SecurityExceptionHandler {
@ExceptionHandler(UsernameNotFoundException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String handleUsernameNotFound(UsernameNotFoundException e) {
return "Username not found";
}
// 可以添加更多针对不同异常的处理方法
}
6. 前端集成(假设使用简单的表单提交):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username"><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password"><br>
<input type="submit" value="Login">
</form>
</body>
</html>
7. 权限管理相关的服务类和方法(示例):
import org.springframework.stereotype.Service;
@Service
public class PermissionService {
public boolean hasPermission(String username, String permission) {
// 根据用户和权限进行判断
return true; // 模拟判断结果
}
}
8. 测试用例(示例):
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
class ApplicationTests {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Test
void testPasswordEncoding() {
String password = "testPassword";
String encodedPassword = passwordEncoder.encode(password);
assertTrue(passwordEncoder.matches(password, encodedPassword));
}
}
请注意,以上代码仅为示例,实际应用中需要根据具体的业务需求和技术架构进行调整和完善。
其中:
UserDetailsService 是 Spring Security 框架提供的一个接口,它并非由手动编写,而是在相关的 Spring Security 依赖中已经存在。
代码中声明 implements UserDetailsService 并实现其方法时,编译器会根据您导入的 Spring Security 相关依赖来识别和验证您的实现是否符合该接口的定义。
所以,不需要自己手动去写这个接口的定义部分,只需要专注于实现其中规定的方法。