1. Overview
1.概述
In this quick tutorial, we’ll look at how we can display the logged-in user’s information in Thymeleaf.
在这个快速教程中,我们将看看如何在Thymeleaf中显示登录用户的信息。
We’ll extend the project we built in our Spring Security with Thymeleaf article. First, we’ll add a custom model to store user information and the service to retrieve them. After that, we’ll display it using the Spring Security Dialect from the Thymeleaf Extras module.
我们将扩展我们在Spring Security with Thymeleaf文章中构建的项目。首先,我们将添加一个自定义模型来存储用户信息,以及用于检索这些信息的服务。之后,我们将使用Thymeleaf Extras模块中的Spring Security Dialect来显示它。
2. UserDetails Implementation
2.用户详情的执行情况
UserDetails is an interface from Spring Security used to hold non-security-related user information.
UserDetails是Spring Security的一个接口,用于保存与安全无关的用户信息。
We’ll create our implementation of the UserDetails interface with some custom fields as the model for storing our authenticated user details. But, to deal with fewer fields and methods, we’ll extend the default framework implementation, the User class:
我们将创建我们的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 Implementation
3.UserDetailsService的实施
The framework’s UserDetailsService single method interface is responsible for fetching the UserDetails during the authentication process.
该框架的UserDetailsService单一方法接口负责在认证过程中获取UserDetails。
Consequently, to be able to load our CustomUserDetails, we’ll need to implement the UserDetailsService interface. For our example, we’re going to hardcode and store the user details in a Map having the usernames as keys:
因此,为了能够加载我们的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("mark.johnson@email.com")
.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("james.davis@email.com")
.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;
}
}
In addition, for implementing the required loadUserByUsername() method, we’re fetching the corresponding CustomUserDetails object from the registry Map by username. However, the user details would be stored and retrieved from a repository in a production environment.
此外,为了实现所需的loadUserByUsername()方法,我们通过用户名从注册表Map获取相应的CustomUserDetails对象。然而,在生产环境中,用户的详细信息将被存储并从存储库中获取。
4. Spring Security Configuration
4.Spring安全配置
Firstly, we need to add the UserDetailsService in Spring Security’s configuration, which will be wired to the CustomUserDetailsService implementation. Further, we’ll set it on the HttpSecurity instance through the corresponding method. The rest is just minimal security configuration requiring the user to be authenticated and configuring /login, /logout, and /index endpoints:
首先,我们需要在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)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successForwardUrl("/index")
.and()
.logout()
.permitAll()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
return http.build();
}
}
5. Display Logged-in User Information
5.显示已登录的用户信息
The Thymeleaf Extras module gives access to the Authentication object, and with the Security Dialect, we can display logged-in user information on Thymelef pages.
Thymeleaf Extras模块允许访问Authentication对象,通过安全方言,我们可以在Thymelef页面上显示登录的用户信息。
The CustomUserDetails object is accessible through the principal field on the Authentication object. For instance, we can access the firstName field using sec:authentication=”principal.firstName”:
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>
Alternatively, an equivalent syntax for writing the Security Dialect expressions without the sec:authentication attribute is using the Spring Expression Language. Therefore, we could display the firstName field using Spring Expression Language format if we are more comfortable with it:
另外,编写没有sec:authentication属性的安全方言表达式的同等语法是使用Spring表达式语言。因此,如果我们更习惯于使用Spring表达式语言的格式,我们可以用它来显示firstName字段。
<div th:text="${#authentication.principal.firstName}"></div>
6. Conclusion
6.结论
In this article, we’ve seen how we can display the logged-in user’s information in Thymeleaf using Spring Security’s support in a Spring Boot application.
在这篇文章中,我们看到了如何在Spring Boot应用程序中使用Spring Security的支持在Thymeleaf中显示登录用户的信息。
As always, the source code for the examples is available over on GitHub.
像往常一样,这些例子的源代码可以在GitHub上找到。