在 Web 应用程序开发中,有两个单独的模块是很常见的 - 一个用于管理员用户,一个用于普通用户。每个模块都有一个单独的登录页面,并且可以与相同或不同的身份验证源相关联。换句话说,应用程序为不同类型的用户提供了多个登录页面:管理员和用户,或管理员和客户。在这篇 Spring Boot 文章中,我想与您分享如何使用 Spring Security 编写此类身份验证代码。在详细信息中,您将了解:
- 如何为具有相同身份验证源的管理员用户和普通用户实现登录页面
- 如何为具有不同身份验证源的管理员和客户实现登录页面
在这两种情况下,我还展示了不同 Spring Boot 和 Spring Security 版本的代码示例,即 Spring Boot 版本 2.7.0 及更早版本:Spring Boot 2.7.0+ 附带 Spring Security 5.7.1+,它不推荐使用WebSecurityConfigurerAdapter和仍然支持它的旧版本。请注意,为了简单起见,我在下面的代码示例中使用了 H2 内存中数据库和纯文本密码。实际上,您可以轻松地切换到物理数据库,例如MySQL。
1. 设置项目的依赖关系
如果使用 Maven,请确保为项目包含以下依赖项:这意味着我们使用 Spring Web、Spring Data JPA、Spring Security、Thymeleaf、Thymeleaf Extras for Spring Security 和 H2 数据库。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-data-jpa</ artifactId >
</ dependency >
< 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-springsecurity5</ artifactId >
</ dependency >
< dependency >
< groupId >com.h2database</ groupId >
< artifactId >h2</ artifactId >
< scope >runtime</ scope >
</ dependency >
|
2. 使用相同的身份验证提供程序实现多个登录页面
在此方案中,我们将对管理员登录页面和用户登录页面进行编码 - 两者都共享相同的身份验证源(用户凭据存储在单个表中)。角色名称用于区分管理员用户 (ADMIN) 或普通用户 (USER)。因此,按如下方式定义角色枚举类型:并按如下方式对用户实体类进行编码:
1
2
3
|
package net.codejava;
public enum Role { ADMIN, USER }
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package net.codejava;
import javax.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false, unique = true, length = 40)
private String email;
@Column(nullable = false, unique = true, length = 10)
private String password;
@Enumerated(EnumType.STRING)
private Role role;
public User() {}
public User(String email, String password, Role role) {
this.email = email;
this.password = password;
this.role = role;
}
// getters and setters are not shown for brevity
}
|
接下来,为数据访问层编写UserRepository接口代码:我们需要一些示例数据用于测试目的。因此,编写以下类,该类将在应用程序启动时初始化数据库:您会看到,它将 4 个用户保存到数据库中:其中两个具有角色 ADMIN,两个具有角色 USER - 密码为纯文本。要实现身份验证,请创建一个类型为UserDetails的类,如下所示:并按如下方式编写UserDetailsService类型的类:
1
2
3
4
5
6
7
8
9
|
package net.codejava;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends CrudRepository<User, Integer> {
public User findByEmail(String email);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package net.codejava;
import java.util.List;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DatabaseLoader {
private UserRepository repo;
public DatabaseLoader(UserRepository repo) {
this .repo = repo;
}
@Bean
public CommandLineRunner initializeDatabase() {
return args -> {
User user1 = new User( "david@gmail.com" , "david123" , Role.ADMIN);
User user2 = new User( "john@yahoo.com" , "john2020" , Role.ADMIN);
User user3 = new User( "nam@codejava.net" , "nam2022" , Role.USER);
User user4 = new User( "ravi@gmail.com" , "ravi2121" , Role.USER);
repo.saveAll(List.of(user1, user2, user3, user4));
System.out.println( "Database initialized" );
};
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package net.codejava;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class CustomUserDetails implements UserDetails {
private User user;
public CustomUserDetails(User user) {
this .user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add( new SimpleGrantedAuthority(user.getRole().toString()));
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true ;
}
@Override
public boolean isAccountNonLocked() {
return true ;
}
@Override
public boolean isCredentialsNonExpired() {
return true ;
}
@Override
public boolean isEnabled() {
return true ;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.codejava;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.*s;
public class CustomUserDetailsService implements UserDetailsService {
@Autowired private UserRepository repo;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = repo.findByEmail(email);
if (user == null ) {
throw new UsernameNotFoundException( "No user found with the given email" );
}
return new CustomUserDetails(user);
}
}
|
为管理员用户实现登录页面
现在,创建一个 Spring 安全配置类,用于为管理员用户配置身份验证提供程序和登录页面。代码如下:你看,这个安全配置类扩展了WebSecurityConfigurerAdapter类,这意味着它应该与低于 2.7.0 的 Spring 引导版本和低于 5.7.1 的 Spring 安全版本一起使用。例如,Spring Boot 版本 2.3.4:让我解释一下这个配置类中的代码:它声明了两个 Spring bean,类型分别为UserDetailsService和PasswordEncoder,身份验证提供程序将使用它们来对用户进行身份验证。以下语句允许对应用程序主页的公共访问(所有人):因为在主页上,我们显示如下所示的登录选项:下面是主页的代码(src/main/resources/templates/index.html):以下语句将 Spring 安全性过滤器链应用于路径以 /admin/ 开头的所有请求:这意味着我们应该将所有管理页面放在 /admin/ path 下。下一条语句要求对所有请求进行身份验证 - 用户必须具有角色 ADMIN 才能访问管理页面:要了解配置登录页面的其余代码,请参阅本文。供您参考,以下是管理员登录页面 (templates/admin/admin_login.html) 的代码:管理员登录页面如下所示:如果您输入管理员用户的正确凭据(请参阅DatabaseLoader类),您将看到管理员主页:然后单击注销按钮注销。管理员主页 (templates/admin/admin_home.html) 的代码如下:如果您使用的是 Spring Boot 版本 >= 2.70 或 Spring Security 版本 >= 5.7.1,则需要对AdminSecurityConfig类使用以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package net.codejava.admin;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.*;
import net.codejava.CustomUserDetailsService;
@Configuration
@Order ( 1 )
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers( "/" ).permitAll();
http.antMatcher( "/admin/**" )
.authorizeRequests().anyRequest().hasAuthority( "ADMIN" )
.and()
.formLogin()
.loginPage( "/admin/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/admin/login" )
.defaultSuccessUrl( "/admin/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/admin/logout" )
.logoutSuccessUrl( "/" );
}
}
|
1
2
3
4
5
6
|
< parent >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-parent</ artifactId >
< version >2.3.4.RELEASE</ version >
< relativePath /> <!-- lookup parent from repository -->
</ parent >
|
1
|
http.authorizeRequests().antMatchers( "/" ).permitAll();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!DOCTYPE html>
< html >
< head >
< meta charset = "ISO-8859-1" >
< title >Spring Multiple Login Pages Demo</ title >
</ head >
< body >
< div align = "center" >
< h2 >Welcome to CodeJava.net</ h2 >
< h4 >< a th:href = "/@{/admin/login}" >Admin Login</ a ></ h4 >
< p />
< h4 >< a th:href = "/@{/user/login}" >User Login</ a ></ h4 >
</ div >
</ body >
</ html >
|
1
|
http.antMatcher( "/admin/**" )
|
1
|
.authorizeRequests().anyRequest().hasAuthority( "ADMIN" )
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!DOCTYPE html>
< html xmlns:th = "http://www.thymeleaf.org" >
< head >
< meta charset = "ISO-8859-1" >
< title >Admin Login - CodeJava.net</ title >
</ head >
< body >
< form th:action = "@{/admin/login}" method = "post" style = "max-width: 400px; margin: 0 auto;" >
< h2 >Admin Login - CodeJava.net</ h2 >
< div th:if = "${param.error}" >
< h4 style = "color: red" >[[${session.SPRING_SECURITY_LAST_EXCEPTION.message}]]</ h4 >
</ div >
< table >
< tr >
< td >E-mail: </ td >
< td >< input type = "email" name = "email" required /></ td >
</ tr >
< tr >
< td >Password: </ td >
< td >< input type = "password" name = "password" required /></ td >
</ tr >
< tr >< td > </ td ></ tr >
< tr >
< td colspan = "2" align = "center" >< input type = "submit" value = "Login" /></ td >
</ tr >
</ table >
</ form >
</ body >
</ html >
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!DOCTYPE html>
< html xmlns:th = "http://www.thymeleaf.org" >
< head >
< meta charset = "ISO-8859-1" >
< title >Welcome to CodeJava.net Admin Control Panel</ title >
</ head >
< body >
< div align = "center" >
< h2 >Welcome to CodeJava.net Admin Control Panel</ h2 >
< p >Your user name is: < b >[[${#request.userPrincipal.principal.username}]]</ b ></ p >
< form th:action = "@{/admin/logout}" method = "post" >
< input type = "submit" value = "Logout" />
</ form >
</ div >
</ body >
</ html >
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package net.codejava.admin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.*;
import org.springframework.security.web.SecurityFilterChain;
import net.codejava.CustomUserDetailsService;
@Configuration
@Order ( 1 )
public class AdminSecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers( "/" ).permitAll();
http.antMatcher( "/admin/**" )
.authorizeRequests().anyRequest().hasAuthority( "ADMIN" )
.and()
.formLogin()
.loginPage( "/admin/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/admin/login" )
.defaultSuccessUrl( "/admin/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/admin/logout" )
.logoutSuccessUrl( "/" );
return http.build();
}
}
|
实现普通用户的登录页面
与管理员登录模块类似,我们需要为用户登录模块创建第二个安全配置类,如下所示(下面是 Spring Boot 版本 < 2.7.0 或 Spring Security < 5.7.1 的代码):如果您注意到,我们指定 AdminSecurityConfig 类的过滤顺序为 @Order(1),UserSecurityConfig类为 @Order(2).这意味着将有两个不同的 Spring 安全过滤器:一个用于管理模块,一个用于用户模块。两个筛选器不能具有相同的顺序。供您参考,以下是用户登录页面 (templates/user/user_login.html) 的代码:用户登录页面如以下屏幕截图所示:如果您输入普通用户的正确凭据,您将看到出现用户主页:供您参考,以下是用户主页 (templates/user/user_home.html) 的代码:为了使所有这些工作, 编写控制器类,如下所示:另外,如果您使用 Spring Boot 版本 >= 2.7.0 或 Spring Security >= 5.7.1,则需要按如下方式对UserSecurityConfig类进行编码:请注意,在此方法中,两个 Spring 安全性配置类共享相同的身份验证提供程序和密码编码器。如果您尝试在用户登录页面中使用管理员凭据,您将收到 403 错误,反之亦然。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package net.codejava.user;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@Order ( 2 )
public class UserSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher( "/user/**" )
.authorizeRequests().anyRequest().hasAuthority( "USER" )
.and()
.formLogin()
.loginPage( "/user/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/user/login" )
.defaultSuccessUrl( "/user/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/user/logout" )
.logoutSuccessUrl( "/" );
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!DOCTYPE html>
< html xmlns:th = "http://www.thymeleaf.org" >
< head >
< meta charset = "ISO-8859-1" >
< title >User Login - CodeJava.net</ title >
</ head >
< body >
< form th:action = "@{/user/login}" method = "post" style = "max-width: 400px; margin: 0 auto;" >
< h2 >User Login - CodeJava.net</ h2 >
< div th:if = "${param.error}" >
< h4 style = "color: red" >[[${session.SPRING_SECURITY_LAST_EXCEPTION.message}]]</ h4 >
</ div >
< table >
< tr >
< td >E-mail: </ td >
< td >< input type = "email" name = "email" required /></ td >
</ tr >
< tr >
< td >Password: </ td >
< td >< input type = "password" name = "password" required /></ td >
</ tr >
< tr >< td > </ td ></ tr >
< tr >
< td colspan = "2" align = "center" >< input type = "submit" value = "Login" /></ td >
</ tr >
</ table >
</ form >
</ body >
</ html >
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!DOCTYPE html>
< html xmlns:th = "http://www.thymeleaf.org" >
< head >
< meta charset = "ISO-8859-1" >
< title >Welcome to CodeJava.net</ title >
</ head >
< body >
< div align = "center" >
< h2 >Welcome to CodeJava.net User Home</ h2 >
< p >Your user name is: < b >[[${#request.userPrincipal.principal.username}]]</ b ></ p >
< form th:action = "@{/user/logout}" method = "post" >
< input type = "submit" value = "Logout" />
</ form >
</ div >
</ body >
</ html >
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package net.codejava;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MainController {
@GetMapping ( "" )
public String viewHomePage() {
return "index" ;
}
@GetMapping ( "/admin/login" )
public String viewAdminLoginPage() {
return "admin/admin_login" ;
}
@GetMapping ( "/admin/home" )
public String viewAdminHomePage() {
return "admin/admin_home" ;
}
@GetMapping ( "/user/login" )
public String viewUserLoginPage() {
return "user/user_login" ;
}
@GetMapping ( "/user/home" )
public String viewUserHomePage() {
return "user/user_home" ;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package net.codejava.user;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@Order ( 2 )
public class UserSecurityConfig {
@Bean
public SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
http.antMatcher( "/user/**" )
.authorizeRequests().anyRequest().hasAuthority( "USER" )
.and()
.formLogin()
.loginPage( "/user/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/user/login" )
.defaultSuccessUrl( "/user/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/user/logout" )
.logoutSuccessUrl( "/" );
return http.build();
}
}
|
3. 使用不同的身份验证提供程序实现多个登录页面
在此方案中,我们将实现管理员登录页面和客户登录页面 - 每个页面都使用自己的身份验证源。这意味着管理员身份验证使用用户表中的凭据,客户身份验证使用客户表中的凭据。首先,更新用户实体类(删除角色枚举),如下所示:然后更新CustomUserDetails类的getAuthority() 方法:CustomUserDetailsService类的代码保持不变。并添加表示客户用户的 Customer 实体类:并按如下所示创建CustomerRepository接口:对于示例数据库,对DatabaseLoader类进行编码,如下所示:您会看到,此代码保留了两个管理员用户和两个具有纯文本密码的客户。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package net.codejava.admin;
import javax.persistence.*;
@Entity
@Table (name = "users" )
public class User {
@Id @GeneratedValue (strategy = GenerationType.IDENTITY)
private Integer id;
@Column (nullable = false , unique = true , length = 40 )
private String email;
@Column (nullable = false , length = 10 )
private String password;
public User() {}
public User(String email, String password) {
this .email = email;
this .password = password;
}
// getters and setters are not shown for brevity
}
|
1
2
3
4
|
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null ;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package net.codejava.customer;
import javax.persistence.*;
@Entity
@Table (name = "customers" )
public class Customer {
@Id @GeneratedValue (strategy = GenerationType.IDENTITY)
private Integer id;
@Column (nullable = false , unique = true , length = 40 )
private String email;
@Column (nullable = false , length = 10 )
private String password;
@Column (nullable = false , length = 30 )
private String fullName;
public Customer() { }
public Customer(String email, String password, String fullName) {
this .email = email;
this .password = password;
this .fullName = fullName;
}
// getters and setters are not shown for brevity
}
|
1
2
3
4
5
6
7
8
9
|
package net.codejava.customer;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CustomerRepository extends CrudRepository<Customer, Integer> {
public Customer findByEmail(String email);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package net.codejava;
import java.util.List;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.*;
import net.codejava.admin.*;
import net.codejava.customer.*;
@Configuration
public class DatabaseLoader {
private UserRepository userRepo;
private CustomerRepository customerRepo;
public DatabaseLoader(UserRepository userRepo, CustomerRepository customerRepo) {
this .userRepo = userRepo;
this .customerRepo = customerRepo;
}
@Bean
public CommandLineRunner initializeDatabase() {
return args -> {
User user1 = new User( "david@gmail.com" , "david123" );
User user2 = new User( "john@yahoo.com" , "john2020" );
userRepo.saveAll(List.of(user1, user2));
Customer customer1 = new Customer( "alex@gmail.com" , "alex123" , "Alex Stevenson" );
Customer customer2 = new Customer( "peter@mail.ru" , "peter246" , "Peter Senkovski" );
customerRepo.saveAll(List.of(customer1, customer2));
System.out.println( "Database initialized" );
};
}
}
|
为管理员用户实现登录页面
要实现管理模块的身份验证,请按如下方式对AdminSecurityConfig类进行编码(对于 Spring 引导版本 >= 2.7.0 或 Spring Security >= 5.7.1):请注意,HTML 页面的代码与上一节中所示的代码相同。如果您使用 Spring 引导版本 < 2.7.0 或 Spring 安全< 5.7.1,请使用以下代码作为安全配置类:如您所见,我们定义了一个身份验证提供程序,以便为管理员登录提供单独的身份验证源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package net.codejava.admin;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.*;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@Order ( 1 )
public class AdminSecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
public DaoAuthenticationProvider authenticationProvider1() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
http.authenticationProvider(authenticationProvider1());
http.authorizeRequests().antMatchers( "/" ).permitAll();
http.antMatcher( "/admin/**" )
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginPage( "/admin/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/admin/login" )
.defaultSuccessUrl( "/admin/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/admin/logout" )
.logoutSuccessUrl( "/" );
return http.build();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
package net.codejava.admin;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.*;
@Configuration
@Order ( 1 )
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
public DaoAuthenticationProvider authenticationProvider1() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authenticationProvider(authenticationProvider1());
http.authorizeRequests().antMatchers( "/" ).permitAll();
http.antMatcher( "/admin/**" )
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginPage( "/admin/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/admin/login" )
.defaultSuccessUrl( "/admin/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/admin/logout" )
.logoutSuccessUrl( "/" );
}
}
|
为客户实现登录页面
与管理模块类似,对 CustomerUserDetails类进行编码,如下所示:以及CustomerUserDetailsService类的代码:下面是客户身份验证模块的安全配置类的代码,适用于 Spring 引导版本 >= 2.70 或 Spring 安全 >= 5.7.1:如果您使用 Spring 引导版本 < 2.70 或 Spring 安全版本 < 5.7.1, 对CustomerSecurityConfig类使用以下代码:如您所见,我们定义了不同的UserDetailsService、PasswordEncoder和AuthenticationProvider,以便为客户登录模块使用单独的身份验证源。并且视图页面和控制器类的代码与前面的代码类似。这是一些代码示例,向您展示如何使用 Spring 安全性实现多个登录页面,涵盖了两种场景:管理员用户和普通用户共享同一个身份验证提供程序;以及使用不同身份验证源的管理员用户和客户用户。希望这篇文章对您有所帮助。感谢您 reading.PS:要了解编码的实际效果,我建议您观看以下视频:文章来源:https://www.toymoban.com/news/detail-422174.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package net.codejava.customer;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class CustomerUserDetails implements UserDetails {
private Customer customer;
public CustomerUserDetails(Customer customer) {
this .customer = customer;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null ;
}
@Override
public String getPassword() {
return customer.getPassword();
}
@Override
public String getUsername() {
return customer.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true ;
}
@Override
public boolean isAccountNonLocked() {
return true ;
}
@Override
public boolean isCredentialsNonExpired() {
return true ;
}
@Override
public boolean isEnabled() {
return true ;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package net.codejava.customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.*;
public class CustomerUserDetailsService implements UserDetailsService {
@Autowired private CustomerRepository repo;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Customer customer = repo.findByEmail(email);
if (customer == null ) {
throw new UsernameNotFoundException( "No customer found with the given email." );
}
return new CustomerUserDetails(customer);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package net.codejava.customer;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.*;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@Order ( 2 )
public class CustomerSecurityConfig {
@Bean
public UserDetailsService customerUserDetailsService() {
return new CustomerUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder2() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
public DaoAuthenticationProvider authenticationProvider2() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(customerUserDetailsService());
authProvider.setPasswordEncoder(passwordEncoder2());
return authProvider;
}
@Bean
public SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
http.authenticationProvider(authenticationProvider2());
http.antMatcher( "/customer/**" )
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginPage( "/customer/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/customer/login" )
.defaultSuccessUrl( "/customer/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/customer/logout" )
.logoutSuccessUrl( "/" );
return http.build();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package net.codejava.customer;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.*;
@Configuration
@Order ( 2 )
public class CustomerSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService customerUserDetailsService() {
return new CustomerUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder2() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
public DaoAuthenticationProvider authenticationProvider2() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(customerUserDetailsService());
authProvider.setPasswordEncoder(passwordEncoder2());
return authProvider;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authenticationProvider(authenticationProvider2());
http.antMatcher( "/customer/**" )
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginPage( "/customer/login" )
.usernameParameter( "email" )
.loginProcessingUrl( "/customer/login" )
.defaultSuccessUrl( "/customer/home" )
.permitAll()
.and()
.logout()
.logoutUrl( "/customer/logout" )
.logoutSuccessUrl( "/" );
}
}
|
文章来源地址https://www.toymoban.com/news/detail-422174.html SpringBootMultipleLoginExamples.zip |
[示例弹簧启动项目] | 426 千字节 |
到了这里,关于Spring Security多登录页面示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!