1. 概述
在这个快速教程中,我们将探讨如何在Thymeleaf中显示已登录用户的详细信息。
我们将基于我们在Spring Security与Thymeleaf集成文章中构建的项目进行扩展。首先,我们将添加一个自定义模型来存储用户信息,并实现获取它们的服务。然后,我们将使用Thymeleaf Extensions模块的Spring Security方言来展示这些信息。
2. UserDetails
实现
UserDetails
是Spring Security提供的接口,用于存储与安全无关的用户信息。
我们将创建一个UserDetails
接口的自定义实现,其中包含一些用于存储已认证用户详细信息的自定义字段。为了处理较少的字段和方法,我们将继承默认框架实现——User
类:
public class CustomUserDetails extends User {
private final String firstName;
private final String lastName;
private final String email;
private CustomUserDetails(Builder builder) {
super(builder.username, builder.password, builder.authorities);
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.email = builder.email;
}
// omitting getters and static Builder class
}
3. UserDetailsService
实现
框架的UserDetailsService
单方法接口负责在身份验证过程中获取UserDetails
。
因此,为了加载我们的CustomUserDetails
,我们需要实现UserDetailsService
接口。在示例中,我们将硬编码并存储用户详细信息在一个以用户名为键的Map
中:
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
private final Map<String, CustomUserDetails> userRegistry = new HashMap<>();
// omitting constructor
@PostConstruct
public void init() {
userRegistry.put("user", new CustomUserDetails.Builder().withFirstName("Mark")
.withLastName("Johnson")
.withEmail("[email protected]")
.withUsername("user")
.withPassword(passwordEncoder.encode("password"))
.withAuthorities(Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")))
.build());
userRegistry.put("admin", new CustomUserDetails.Builder().withFirstName("James")
.withLastName("Davis")
.withEmail("[email protected]")
.withUsername("admin")
.withPassword(passwordEncoder.encode("password"))
.withAuthorities(Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN")))
.build());
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
CustomUserDetails userDetails = userRegistry.get(username);
if (userDetails == null) {
throw new UsernameNotFoundException(username);
}
return userDetails;
}
}
此外,为了实现所需的loadUserByUsername()
方法,我们将通过用户名从注册表Map
中获取相应的CustomUserDetails
对象。但在生产环境中,用户详细信息将存储和从仓库中检索。
4. Spring Security 配置
首先,我们需要在Spring Security配置中添加UserDetailsService
,并与CustomUserDetailsService
实现关联。然后,我们通过相应的方法将其设置到HttpSecurity
实例上。其余的只是基本的安全配置,要求用户进行身份验证,并配置/login
、/logout
和/index
端点:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
private final UserDetailsService userDetailsService;
// omitting constructor
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsService)
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry
.anyRequest().authenticated())
.formLogin(httpSecurityFormLoginConfigurer -> httpSecurityFormLoginConfigurer
.loginPage("/login").permitAll()
.defaultSuccessUrl("/index"))
.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer.permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login"));
return http.build();
}
}
5. 显示已登录用户信息
Thymeleaf Extensions模块提供了对Authentication
对象的访问,通过Security Dialect,我们可以在Thymeleaf页面上显示已登录用户的详细信息。
CustomUserDetails
对象可以通过Authentication
对象的principal
字段访问。例如,我们可以使用sec:authentication=”principal.firstName”
来访问firstName
字段:
<!DOCTYPE html>
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<title>Welcome to Spring Security Thymeleaf tutorial</title>
</head>
<body>
<h2>Welcome</h2>
<p>Spring Security Thymeleaf tutorial</p>
<div sec:authorize="hasRole('USER')">Text visible to user.</div>
<div sec:authorize="hasRole('ADMIN')">Text visible to admin.</div>
<div sec:authorize="isAuthenticated()">Text visible only to authenticated users.</div>
Authenticated username:
<div sec:authentication="name"></div>
Authenticated user's firstName:
<div sec:authentication="principal.firstName"></div>
Authenticated user's lastName:
<div sec:authentication="principal.lastName"></div>
Authenticated user's email:
<div sec:authentication="principal.lastName"></div>
Authenticated user roles:
<div sec:authentication="principal.authorities"></div>
</body>
</html>
另一种等效的语法是在不使用sec:authentication
属性的情况下编写Security Dialect表达式,即使用Spring Expression Language。如果我们更熟悉Spring Expression Language,我们可以使用其格式显示firstName
字段:
<div th:text="${#authentication.principal.firstName}"></div>
6. 总结
在这篇文章中,我们了解了如何在Spring Boot应用中使用Spring Security的支持在Thymeleaf中显示已登录用户的详细信息。
如往常一样,示例代码可在GitHub上找到:https://github.com/eugenp/tutorials/tree/master/spring-security-modules/spring-security-web-thymeleaf。