Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the process of Security login authentication

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces the relevant knowledge of "what is the process of Security login authentication". The editor shows you the operation process through an actual case. The operation method is simple, fast and practical. I hope this article "what is the process of Security login authentication" can help you solve the problem.

1. Preface: flow chart:

Second, the front desk sends the request

The user submits the user name and password to the / login interface using POST. / login is the default interface when not specified

3. Request arrives at UsernamePasswordAuthenticationFilter filter

The request will first come to: UsernamePasswordAuthenticationFilter

/ * * UsernamePasswordAuthenticationFilter: handle authentication form submission and encapsulate the request information as Authentication and return it to the upper parent class, which passes through SecurityContextHolder.getContext (). SetAuthentication (authResult); save the verified Authentication to the security context * / public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username"; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password" Private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher ("/ login", "POST"); / / you can modify private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; private boolean postOnly = true through the corresponding set method / / initialize a user password authentication filter the default login uri is / login request method is POST public UsernamePasswordAuthenticationFilter () {super (DEFAULT_ANT_PATH_REQUEST_MATCHER);} public UsernamePasswordAuthenticationFilter (AuthenticationManager authenticationManager) {super (DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager) } @ Override public Authentication attemptAuthentication (HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (this.postOnly & &! request.getMethod (). Equals ("POST")) {throw new AuthenticationServiceException ("Authentication method not supported:" + request.getMethod ());} String username = obtainUsername (request) Username = (username! = null)? Username: ""; username = username.trim (); String password = obtainPassword (request); password = (password! = null)? Password: ""; / / encapsulate the account name and password into an authentication Token object. This is a pass, but the status is not trusted at this time, and it will become trusted UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken (username, password) only after passing the authentication. / / Allow subclasses to set the "details" property / / records the remote address and sets the session ID setDetails (request, authRequest) if the session already exists (it will not be created); / / authenticates the Token using the AuthenticationManager in the parent class return this.getAuthenticationManager () .authenticate (authRequest) } / * * obtainUsername and obtainPassword are convenient to get username and password from request. In fact, if we don't use most of them in front-end separation projects. Because the JSON data is passed from the front end, we usually use the JSON utility class to parse * / @ Nullable protected String obtainPassword (HttpServletRequest request) {return request.getParameter (this.passwordParameter);} @ Nullable protected String obtainUsername (HttpServletRequest request) {return request.getParameter (this.usernameParameter) } / * * provide details that subclasses can configure to place authentication requests * / protected void setDetails (HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {authRequest.setDetails (this.authenticationDetailsSource.buildDetails (request));} / * *. Omit some unimportant codes set get * /} IV. Make UsernamePasswordAuthenticationToken

Make the acquired data into a token UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken (username, password)

We mentioned in the figure that we are actually encapsulating an Authentication object, and UsernamePasswordAuthenticationToken is a default implementation class.

Let's take a brief look at their structure diagram:

Public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; / / this is how to rewrite private final Object principal; private Object credentials according to your own needs when the user name and password are customized. / * * / encapsulate the account name and password into an authentication UsernamePasswordAuthenticationToken object. This is a pass, but the status at this time cannot be trusted. / / We can also see here that the permission is null, setAuthenticated (false); it means that the identity is unverified at this time, so the status is not trusted at this time * / public UsernamePasswordAuthenticationToken (Object principal, Object credentials) {super (null) This.principal = principal; this.credentials = credentials; setAuthenticated (false);} / * * this is the trusted state * / public UsernamePasswordAuthenticationToken (Object principal, Object credentials, Collection authentication);}

Note: boolean supports (Class authentication); the comments for the complete JavaDoc in the way are:

If more than one AuthenticationProvider supports the same Authentication object, the first Provder that can successfully validate the Authentication will populate its properties and return the result, overwriting any possible AuthenticationException thrown by the previously supported AuthenticationProvider. Once validated successfully, no subsequent AuthenticationProvider will be attempted. If none of the AuthenticationProvider successfully validates the Authentication, the AuthenticationException thrown by the last Provider will be thrown. (AuthenticationProvider can be configured in the Spring Security configuration class)

Machine translation is not easy to understand, let's translate it into a bit easier to understand:

Of course, sometimes we have several different AuthenticationProvider, each of which supports different Authentication objects, so when a specific AuthenticationProvier is passed into the interior of the ProviderManager, we will select its corresponding supported provider from the AuthenticationProvider list to verify the corresponding Authentication object.

This knowledge is related to the implementation of multiple login methods, and I will briefly talk about my understanding.

What we are talking about here is the default login method, which uses UsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationToken and DaoAuthenticationProvider later for identity verification, but if we need to add SMS verification code login or email verification code or third-party login and so on.

Then we will also re-inherit AbstractAuthenticationProcessingFilter, AbstractAuthenticationToken and AuthenticationProvider for rewriting, because different login methods have different authentication logic and different AuthenticationProvider. We log in with username and password. Security provides a simple implementation of AuthenticationProvider, DaoAuthenticationProvider, which uses a UserDetailsService to query username, password and GrantedAuthority. In practice, we will implement the UserDetailsService interface to query relevant user information from the database. The authentication core of AuthenticationProvider is to load the corresponding UserDetails to check whether the password entered by the user matches it.

The flow chart is roughly as follows:

VIII. DaoAuthenticationProvider

AuthenticationProvider has a lot of implementation classes and inheritance classes. If we look directly at the ones related to User, we will first find the abstract class AbstractUserDetailsAuthenticationProvider.

Let's look at this abstract class first, and then look at its implementation class to see how they progress step by step.

/ * * A basic AuthenticationProvider that allows subclasses to override and use UserDetails objects. This class is designed to respond to UsernamePasswordAuthenticationToken authentication requests. After the verification is successful, the UsernamePasswordAuthenticationToken is created and returned to the caller. The token takes as its principal either the String representation of the user name or the UserDetails returned from the authentication repository. * / public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {/ /... Omitted some code private UserCache userCache = new NullUserCache (); private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper () / / Authentication method @ Override public Authentication authenticate (Authentication authentication) throws AuthenticationException {Assert.isInstanceOf (UsernamePasswordAuthenticationToken.class, authentication, ()-> this.messages.getMessage ("AbstractUserDetailsAuthenticationProvider.onlySupports", "Only UsernamePasswordAuthenticationToken is supported")) / / determine whether the user name is empty String username = determineUsername (authentication); boolean cacheWasUsed = true; / / first check the cache UserDetails user = this.userCache.getUserFromCache (username); if (user = = null) {cacheWasUsed = false Try {user = retrieveUser (username, (UsernamePasswordAuthenticationToken) authentication);} catch (UsernameNotFoundException ex) {this.logger.debug ("Failed to find user'" + username + "") If (! this.hideUserNotFoundExceptions) {throw ex;} throw new BadCredentialsException (this.messages .getMessage ("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")) } Assert.notNull (user, "retrieveUser returned null-a violation of the interface contract");} try {/ / some check this.preAuthenticationChecks.check (user); additionalAuthenticationChecks (user, (UsernamePasswordAuthenticationToken) authentication) } catch (AuthenticationException ex) {if (! cacheWasUsed) {throw ex } / / There was a problem, so try again after checking / / we're using latest data (i.e. Not from the cache) cacheWasUsed = false / / retrieveUser is a method without abstraction. Later we'll see how its implementation class is implemented: user = retrieveUser (username, (UsernamePasswordAuthenticationToken) authentication); / / some this.preAuthenticationChecks.check (user) that checks whether information users are available; additionalAuthenticationChecks (user, (UsernamePasswordAuthenticationToken) authentication) } this.postAuthenticationChecks.check (user); if (! cacheWasUsed) {this.userCache.putUserInCache (user);} Object principalToReturn = user; if (this.forcePrincipalAsString) {principalToReturn = user.getUsername () } / / create a successful Authentication object Return createSuccessAuthentication (principalToReturn, authentication, user);} private String determineUsername (Authentication authentication) {return (authentication.getPrincipal () = = null)? "NONE_PROVIDED": authentication.getName ();} / * * create a successful Authentication object. This also allows word classes to be implemented. If you want to encrypt the password, General word classes will be reimplemented * / protected Authentication createSuccessAuthentication (Object principal, Authentication authentication, UserDetails user) {/ / identity information is also added here UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken (principal, authentication.getCredentials (), this.authoritiesMapper.mapAuthorities (user.getAuthorities () Result.setDetails (authentication.getDetails ()); this.logger.debug ("Authenticated user"); return result } / * * allows subclasses to actually retrieve UserDetails from implementation-specific locations. If the credentials provided are incorrect, you can choose to throw AuthenticationException immediately (if you need to bind to a resource as a user to obtain or generate a UserDetails) * / protected abstract UserDetails retrieveUser (String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException; / /.}

DaoAuthenticationProvider: people who really do things

/ * * AuthenticationProvider implementation of retrieving user details from UserDetailsService. * / public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {/ /... Omitted some code / * / @ Override protected final UserDetails retrieveUser (String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {prepareTimingAttackProtection () Try {/ / UserDetailsService is simply the interface to load the corresponding UserDetails (usually from the database), while UserDetails contains more detailed user information / / gets the user information through loadUserByUsername and returns a UserDetails UserDetails loadedUser = this.getUserDetailsService () .loadUserByUsername (username) If (loadedUser = = null) {throw new InternalAuthenticationServiceException ("UserDetailsService returned null, which is an interface contract violation");} return loadedUser } catch (UsernameNotFoundException ex) {mitigateAgainstTimingAttack (authentication); throw ex;} catch (InternalAuthenticationServiceException ex) {throw ex } catch (Exception ex) {throw new InternalAuthenticationServiceException (ex.getMessage (), ex) }} / / re-parent method to encrypt the password @ Override protected Authentication createSuccessAuthentication (Object principal, Authentication authentication, UserDetails user) {boolean upgradeEncoding = this.userDetailsPasswordService! = null & & this.passwordEncoder.upgradeEncoding (user.getPassword ()) If (upgradeEncoding) {String presentedPassword = authentication.getCredentials (). ToString (); String newPassword = this.passwordEncoder.encode (presentedPassword); user = this.userDetailsPasswordService.updatePassword (user, newPassword);} return super.createSuccessAuthentication (principal, authentication, user);} / /.} IX, UserDetailsService and UserDetails interfaces

To put it simply, UserDetailsService defines an interface to load the corresponding UserDetails. In our use, most of us will implement this interface to query relevant user information from the database.

/ / the core interface for loading user-specific data. Public interface UserDetailsService {/ / locate the user UserDetails loadUserByUsername (String username) throws UsernameNotFoundException;} based on the user name

UserDetails is also an interface, and it will also be implemented and customized in actual development.

/ * provide core user information. For security purposes, Spring Security does not use the implementation directly. They simply store user information and then encapsulate it in an Authentication object. This allows non-security-related user information (such as e-mail addresses, phone numbers, etc.) to be stored in a convenient location. * / public interface UserDetails extends Serializable {/ / returns the permissions granted to the user. Collection

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report