In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
How to get started with user information UserDetails in Spring Security, aiming at this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
1. Preface
Starting today, we'll take a step-by-step look at how it works. And how do we handle it.
2. Spring Boot integrates Spring Security
This is a clich é. But in order to take care of most, let's talk about it. Integrating Spring Security only requires the introduction of its corresponding Starter components. Spring Security can protect not only Servlet Web applications, but also Reactive Web applications. In this article, we talk about the former. We just need to introduce the following dependencies in the Spring Security project:
Org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-web org.projectlombok lombok true Org.springframework.boot spring-boot-starter-test test org.springframework.security spring-security-test test 3. UserDetailsServiceAutoConfiguration
To start the project, visiting the Actuator endpoint http://localhost:8080/actuator will jump to a login page http://localhost:8080/login as follows:
You are required to enter the user name Username (default is user) and password Password. The password will be printed in the springboot console like Using generated security password: e1f163be-ad18-4be1-977c-88a6bcee0d37, followed by a long string of passwords, which are not available in production. If you are careful enough to print a log from the console and find out that the random password was generated by the UserDetailsServiceAutoConfiguration configuration class, let's start with it and find out.
3.1 UserDetailsService
UserDetailsService interface. This interface provides only one method:
UserDetails loadUserByUsername (String username) throws UsernameNotFoundException
This method is easy to understand: load the user by user name. This method is mainly used to query from system data and load specific users into Spring Security.
3.2 UserDetails
From the above UserDetailsService can know that it is UserDetails that will eventually be handed over to Spring Security. This interface is the core interface to provide user information. The interface implementation stores only the user's information. Later, the user information provided by this API will be encapsulated into the authentication object Authentication. UserDetails provides by default:
User's permission set. ROLE_ prefix is required by default.
User's encrypted password. If it is not encrypted, the {noop} prefix will be used.
Unique user name within the application
Whether the account expires
Is the account locked?
Whether the voucher expires
Whether the user is available
If the above information is not enough for you to use, you can implement your own extension to store more user information. For example, the user's mailbox, mobile phone number and so on. Usually we use its implementation class:
Org.springframework.security.core.userdetails.User
This class has a built-in builder UserBuilder to help us build UserDetails objects, which we'll use later.
3.3 UserDetailsServiceAutoConfiguration
The fully qualified name of UserDetailsServiceAutoConfiguration is:
Org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
The source code is as follows
@ Configuration@ConditionalOnClass (AuthenticationManager.class) @ ConditionalOnBean (ObjectPostProcessor.class) @ ConditionalOnMissingBean ({AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class}) public class UserDetailsServiceAutoConfiguration {private static final String NOOP_PASSWORD_PREFIX = "{noop}"; private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile ("^\ {. +}. * $"); private static final Log logger = LogFactory.getLog (UserDetailsServiceAutoConfiguration.class) Bean @ ConditionalOnMissingBean (type = "org.springframework.security.oauth3.client.registration.ClientRegistrationRepository") @ Lazy public InMemoryUserDetailsManager inMemoryUserDetailsManager (SecurityProperties properties, ObjectProvider passwordEncoder) {SecurityProperties.User user = properties.getUser (); List roles = user.getRoles () Return new InMemoryUserDetailsManager (User.withUsername (user.getName ()) .password (getOrDeducePassword (user, passwordEncoder.getIfAvailable () .password (StringUtils.toStringArray (roles)) .build ();} private String getOrDeducePassword (SecurityProperties.User user, PasswordEncoder encoder) {String password = user.getPassword () If (user.isPasswordGenerated ()) {logger.info (String.format ("% n%nUsing generated security password:% s% n", user.getPassword ());} if (encoder! = null | | PASSWORD_ALGORITHM_PATTERN.matcher (password). Matches ()) {return password } return NOOP_PASSWORD_PREFIX + password;}}
Let's take a brief look at the class. From the @ Conditional series annotations, we know that this class takes effect when there is AuthenticationManager in the classpath, Bean ObjectPostProcessor in the Spring container, and no Bean AuthenticationManager, AuthenticationProvider, or UserDetailsService. Don't worry about what these classes are for! This class initializes only one Bean of type UserDetailsManager. The UserDetailsManager type is responsible for adding, deleting, querying and modifying the abstract UserDetails of the security user entity. It also inherits the UserDetailsService interface.
I see. Let's turn our attention back to UserDetailsServiceAutoConfiguration. This class initializes a memory user manager named InMemoryUserDetailsManager. The manager injects a default UserDetails into memory through configuration, which is the user we used above, and each time the user is started, it is generated dynamically. So the question is, can we implement the user management logic we need if we define our own UserDetailsManager Bean?
3.4 Custom UserDetailsManager
We customize a UserDetailsManager to see if we can achieve the effect of custom user management. First of all, we implement a proxy for all the methods of UserDetailsManager, and we still store the user in memory, except that this is customized by us:
Package cn.felord.spring.security;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.core.Authentication;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UsernameNotFoundException;import java.util.HashMap;import java.util.Map / * * Agent {@ link org.springframework.security.provisioning.UserDetailsManager} all functions * * @ author Felordcn * / public class UserDetailsRepository {private Map users = new HashMap (); public void createUser (UserDetails user) {users.putIfAbsent (user.getUsername (), user);} public void updateUser (UserDetails user) {users.put (user.getUsername (), user) } public void deleteUser (String username) {users.remove (username);} public void changePassword (String oldPassword, String newPassword) {Authentication currentUser = SecurityContextHolder.getContext () .getAuthentication () If (currentUser = = null) {/ / This would indicate bad coding somewhere throw new AccessDeniedException ("Can't change password as no Authentication object found in context" + "for current user.");} String username = currentUser.getName (); UserDetails user = users.get (username) If (user = = null) {throw new IllegalStateException ("Current user doesn't exist in database.");} / todo copy InMemoryUserDetailsManager implements specific password update logic} public boolean userExists (String username) {return users.containsKey (username);} public UserDetails loadUserByUsername (String username) throws UsernameNotFoundException {return users.get (username);}}
This class is responsible for the specific operation of adding, deleting, modifying and searching UserDetails. We inject it into the Spring container:
@ Bean public UserDetailsRepository userDetailsRepository () {UserDetailsRepository userDetailsRepository = new UserDetailsRepository () / / in order for our login to run, we initialize a user's Felordcn password in clear text when you use the prefix {noop} on password 12345, which means your password does not use encryption. Authorities must not be empty, which represents the user's role permission set UserDetails felordcn = User.withUsername ("Felordcn"). Password ("{noop} 12345") .authorities (AuthorityUtils.NO_AUTHORITIES). Build () UserDetailsRepository.createUser (felordcn); return userDetailsRepository;}
In order to facilitate testing, we also built a UserDetails user named Felordcn password 12345, the password is in clear text when you use the prefix {noop} on password 12345 means your password does not use encryption, we do not specify password encryption here you can use PasswordEncoder to specify an encryption method. Bcrypt is generally recommended as the encryption method. The default Spring Security uses the same method. Authorities must not be null, which represents the user's role permission set. Next we implement a UserDetailsManager and inject the Spring container:
@ Bean public UserDetailsManager userDetailsManager (UserDetailsRepository userDetailsRepository) {return new UserDetailsManager () {@ Override public void createUser (UserDetails user) {userDetailsRepository.createUser (user);} @ Override public void updateUser (UserDetails user) {userDetailsRepository.updateUser (user) } @ Override public void deleteUser (String username) {userDetailsRepository.deleteUser (username);} @ Override public void changePassword (String oldPassword, String newPassword) {userDetailsRepository.changePassword (oldPassword, newPassword) } @ Override public boolean userExists (String username) {return userDetailsRepository.userExists (username);} @ Override public UserDetails loadUserByUsername (String username) throws UsernameNotFoundException {return userDetailsRepository.loadUserByUsername (username);}};}
So the actual execution is delegated to UserDetailsRepository. Let's repeat chapter 3. Enter the login page by typing Felordcn and 12345 respectively.
3.5 Database management users
After the above configuration, I believe that smart you already know how to use the database to manage users. Just replace the users attribute in UserDetailsRepository with an abstract Dao interface, whether you implement it using Jpa or Mybatis.
4. Summary
Today we have some interpretation of the user information in Spring Security related to UserDetails. And the user information processing service is defined. I believe you already know how to load user information in Spring Security and how to expand user information. Later, we will slowly interpret Spring Security from shallow to deep.
This is the answer to the question about how to get started with user information in Spring Security. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.