实现SpringSecurity表单登录需要以下步骤:
- 导入依赖
需要在项目中导入SpringSecurity相关的依赖包,例如:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.5.0</version>
</dependency>
- 配置SpringSecurity
在SpringBoot项目中,可以通过在配置类上加上@EnableWebSecurity
注解,来启用SpringSecurity。接着在配置类中,可以定义拦截器规则、用户信息等相关配置,例如:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
上述配置中,我们配置了一个自定义的用户详情服务MyUserDetailsService
,并且指定了密码加密的实现类BCryptPasswordEncoder
。在configure(HttpSecurity http)
方法中,我们设定了拦截器规则,对于URI为/login
的请求,不需要进行身份验证,对于其他URI的请求,需要进行身份验证。
- 创建登录页面
接下来,创建一个登录页面,代码中含有一个POST请求方法,用于接收用户提交的登录表单。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<div>
<form action="/login" method="POST">
<label for="username">用户名:</label>
<input type="text" id="username" name="username">
<br/>
<label for="password">密码:</label>
<input type="password" id="password" name="password">
<br/>
<input type="submit" value="登录">
</form>
</div>
</body>
<html>
- 实现自定义用户详情服务
在前面的配置中,我们指定了一个自定义的用户详情服务MyUserDetailsService
,需要自己实现该服务来获取用户的详细信息,例如:
@Service
public class MyUserDetailsService 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 + " not found");
}
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), authorities);
}
}
通过自定义用户详情服务,可以使用自己的业务逻辑从数据库或其他持久化层获取用户的信息。上述代码中,我们使用了一个自定义的实体类User
来封装用户的信息,同时也使用了自定义的实体类Role
来封装用户的角色信息。
- 定义自定义登录成功处理器
我们可以定义一个自定义的登录成功处理器来处理登录成功后的相关业务逻辑。例如:
@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
上述代码中,定义了一个CustomAuthenticationSuccessHandler
类,继承了SimpleUrlAuthenticationSuccessHandler
类,并重写了onAuthenticationSuccess
方法。该方法会在用户登录成功后被调用,并可以在该方法中,处理登录成功后的业务逻辑。在该示例中,我们只是简单地设置了HTTP响应状态为200。
示例1:实现SpringSecurity表单登录的完整示例
下面是一个完整的SpringBoot项目中的完整示例:
@SpringBootApplication
public class SpringBootSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSecurityApplication.class, args);
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Service
public class MyUserDetailsService 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 + " not found");
}
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), authorities);
}
}
@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles;
// getter & setter
}
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getter & setter
}
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
}
示例2:使用 Thymeleaf 模板引擎实现 SpringSecurity 表单登录
下面是一个使用Thymeleaf模板引擎的SpringBoot项目中的完整示例:
@SpringBootApplication
public class SpringBootSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSecurityApplication.class, args);
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Service
public class MyUserDetailsService 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 + " not found");
}
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), authorities);
}
}
@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles;
// getter & setter
}
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getter & setter
}
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
@Controller
public class LoginController {
@GetMapping("/login")
public String login() {
return "login";
}
}
@Controller
public class HomeController {
@GetMapping("/home")
public String home() {
return "home";
}
}
}
上述代码中,我们使用了Thymeleaf来实现了一个自定义的登录页面,在该登录页面中,通过表单提交用户名和密码,并将数据提交到/login
URI。同时,也定义了一个自定义的控制器HomeController
,在用户登录成功后,会跳转到该控制器中定义的/home
URI。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity 表单登录的实现 - Python技术站