springboot整合spring security
Spring Security 是基于 Spring 框架的一个安全认证和授权框架,可以对 Web 应用的安全进行管理和控制。
1.Spring Boot 整合 Spring Security 的具体步骤
在 pom.xml 文件中添加 Spring Security 的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
创建一个继承自 WebSecurityConfigurerAdapter 的配置类,并重写 configure() 方法来配置安全规则,例如设置哪些请求需要进行身份认证,哪些请求需要拥有某个角色才能访问等。
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("{noop}admin").roles("ADMIN");
}
}
上述代码定义了访问 /admin/** 的请求需要拥有 ADMIN 角色才能访问,其他请求需要进行身份认证,同时通过 inMemoryAuthentication() 方法进行内存级别的用户认证,用户名为 admin,密码为 admin,拥有 ADMIN 角色。
如果需要使用自定义的用户服务来进行认证,可以在 configure(AuthenticationManagerBuilder auth) 方法中设置用户服务。
@Autowired
private UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
使用自定义的用户服务 userService,对密码进行了BCrypt 加密处理。
2.完整步骤
添加依赖
在 pom.xml 文件中添加 Spring Boot 和 Spring Security 的依赖:
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
创建实体类和数据访问层
创建 User 实体类和 UserRepository 数据访问层:
java
@Entity
@Table(name = "users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String username;
private String password;
private String email;
private boolean enabled;
private LocalDateTime created_at;
// getters and setters
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
创建用户服务
创建 UserDetailsService 实现类 CustomUserDetailsService,实现 loadUserByUsername() 方法来获取用户信息。
java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Username " + username + " not found");
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
user.isEnabled(), true, true, true,
getAuthorities(Arrays.asList(new Role("ROLE_USER"))));
}
private Collection<? extends GrantedAuthority> getAuthorities(Collection<Role> roles) {
return getGrantedAuthorities(getPrivileges(roles));
}
private List<String> getPrivileges(Collection<Role> roles) {
List<String> privileges = new ArrayList<>();
List<Privilege> collection = new ArrayList<>();
for (Role role : roles) {
collection.addAll(role.getPrivileges());
}
for (Privilege item : collection) {
privileges.add(item.getName());
}
return privileges;
}
private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (String privilege : privileges) {
authorities.add(new SimpleGrantedAuthority(privilege));
}
return authorities;
}
}
从 UserRepository 中获取到的 User 对象转换成 Spring Security 的 UserDetails 对象,并为其授权。
创建安全配置类
创建 SecurityConfig 配置类,继承自 WebSecurityConfigurerAdapter,实现 configure() 方法来配置安全规则和自定义用户服务。
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
上述代码定义了访问 /admin/** 的请求需要拥有 ADMIN 角色才能访问,其他请求需要进行身份认证,同时通过自定义的用户服务 CustomUserDetailsService 来进行身份认证,并对密码进行了 BCrypt 加密处理。
创建控制器和模板
创建 HomeController 控制器和 index.html 登录页模板:
java
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "index";
}
@GetMapping("/dashboard")
public String dashboard() {
return "dashboard";
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login Page</title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have logged out successfully.
</div>
<form th:action="@{/login}" method="post">
<div>
<label>Username:</label>
<input type="text" name="username" />
</div>
<div>
<label>Password:</label>
<input type="password" name="password" />
</div>
<div>
<button type="submit">Log in</button>
</div>
</form>
</body>
</html>
运行和测试
启动应用,访问 http://localhost:8080/,会跳转到登录页,输入用户名 admin 和密码 admin,会跳转到 dashboard 页面;访问 http://localhost:8080/admin,需要登录并需要拥有 ADMIN 角色才能访问。