UsernamePasswordAuthenticationToken在Java应用程序中用于身份验证的用法需要解释。

huangapple go评论58阅读模式
英文:

Need Explanation of UsernamePasswordAuthenticationToken Usage in Java Application for Authentication

问题

This code snippet is creating a UsernamePasswordAuthenticationToken object in a Java application. It appears to be related to authentication. Here's the translated code:

// 创建一个UsernamePasswordAuthenticationToken对象
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
    userDetails, null,
    userDetails == null ?
        List.of() : userDetails.getAuthorities()
);

The code is constructing an authentication object using the UsernamePasswordAuthenticationToken class. It takes userDetails as the principal (user) information, null for credentials (password), and it sets the authorities based on the condition:

  • If userDetails is null, it sets the authorities to an empty list using List.of().
  • If userDetails is not null, it sets the authorities using userDetails.getAuthorities().

This code is typically used in Spring Security for handling user authentication, where userDetails would contain information about the user being authenticated, and authorities represent the user's roles and permissions.

英文:

Could someone please provide an explanation for the following code that uses UsernamePasswordAuthenticationToken in a Java application?

UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
    userDetails, null,
    userDetails == null ?
        List.of() : userDetails.getAuthorities()
);

I'm trying to understand how UsernamePasswordAuthenticationToken is used in this code to handle authentication, particularly with regards to the userDetails parameter and the null value passed as credentials. I'm also curious about the use of List.of() and userDetails.getAuthorities() for setting the authorities. Any insights would be helpful. Thank you!

答案1

得分: 2

The UsernamePasswordAuthenticationToken Authentication implementation has two constructor options:

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

	// This constructor can be safely used by any code that wishes to create a
	// UsernamePasswordAuthenticationToken, as the isAuthenticated()
	// will return false.
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
		super(null); // null is being passed to the authorities parameter
		this.principal = principal;
		this.credentials = credentials;
		setAuthenticated(false);
	}

	// This constructor should only be used by AuthenticationManager or
	// AuthenticationProvider implementations that are satisfied with
	// producing a trusted (i.e. isAuthenticated() = true) authentication token.
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
			Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
		this.principal = principal;
		this.credentials = credentials;
		super.setAuthenticated(true); // must use super, as we override
	}

    // ...
}

The first one is used to carry the authentication data, obtained from the request, to be authenticated by an AuthenticationProvider capable of performing the username-password style of authentication, no matter what your users' usernames are, whether they're an actual username or an email, phone number, id, etc. You can define it in a UserDetailsService implementation.

The second one, which gets three arguments, sets the user authentication into Spring Security's Security Context Holder. Basically, by virtue of just adding the granted authorities list to the constructor, you're saying that the user has been successfully authenticated, even though the list is empty.

That being said, there's no need to keep the user credentials stored anymore. In fact, keeping the user credentials stored would be a security breach, as your Authentication object carries the user's password as it is, i.e., not hashed.

The UsernamePasswordAuthenticationToken class actually has two factory methods, that can, and in fact should, be used to explicitly build an authenticated or unauthenticated token, the authenticated() and unauthenticated():

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

	// Omitted constructors and fields for brevity

	// This factory method can be safely used by any code that wishes to create an
	// unauthenticated UsernamePasswordAuthenticationToken.
	public static UsernamePasswordAuthenticationToken unauthenticated(Object principal, Object credentials) {
		return new UsernamePasswordAuthenticationToken(principal, credentials);
	}

	// This factory method can be safely used by any code that wishes to create an
	// authenticated UsernamePasswordAuthenticationToken.
	public static UsernamePasswordAuthenticationToken authenticated(Object principal, Object credentials,
			Collection<? extends GrantedAuthority> authorities) {
		return new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
	}
}

If a developer leverages the Spring Security implementation of the AuthenticationManager -- the ProviderManager --, and of the AuthenticationProvider -- which for the username-password style of authentication is the DaoAuthenticationProvider --, they can rest assured that the user's credentials will be erased anyways before the authentication is set into the SecurityContextHolder. The ProviderManager class invokes the eraseCredentials() method, from the CredentialsContainer functional interface, to erase the credentials from the authenticated token.

I highly recommend that you use what the Spring Security team has already implemented, as their implementations were already tested and proven to be secure.

If you want to know more about the Spring Security Authentication Architecture, you can take a look at this page of the Spring Security reference documentation.

英文:

The UsernamePasswordAuthenticationToken Authentication implementation has two constructor options:

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

/**
	 * This constructor can be safely used by any code that wishes to create a
	 * UsernamePasswordAuthenticationToken, as the isAuthenticated()
	 * will return false.
	 *
	 */
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
		super(null); // null is being passed to the authorities parameter
		this.principal = principal;
		this.credentials = credentials;
		setAuthenticated(false);
	}

	/**
	 * This constructor should only be used by AuthenticationManager or
	 * AuthenticationProvider implementations that are satisfied with
	 * producing a trusted (i.e. isAuthenticated() = true) authentication token.
	 * 
	 */
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
			Collection&lt;? extends GrantedAuthority&gt; authorities) {
		super(authorities);
		this.principal = principal;
		this.credentials = credentials;
		super.setAuthenticated(true); // must use super, as we override
	}

    // ...
}

The first one is used to carry the authentication data, obtained from the request, to be authenticated by an AuthenticationProvider capable of performing the username-password style of authentication, no matter what your users' username are, whether they're an actual username or an email, phone number, id, etc. You can define it in a UserDetailsService implementation.

The second one, which gets three arguments, sets the user authentication into the Spring Security's Security Context Holder. Basically, by virtue of just adding the granted authorities list to the constructor, you're saying that the users has been successfully authenticated, even though the list is empty.

That being said, there's no need to keep the user credentials stored anywhere no more. In fact, keep the user credentials stored would be a security breach, as your Authentication object carries the user's password as it is, i.e., not hashed.

The UsernamePasswordAuthenticationToken class actually has two factory methods, that can, and in fact should, be used to explicitly build an authenticated or unauthenticated token, the authenticated() and unauthenticated():


public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

	// Omitted constructors and fields for brevity

	/**
	 * This factory method can be safely used by any code that wishes to create a
	 * unauthenticated UsernamePasswordAuthenticationToken.
	 *
	 */
	public static UsernamePasswordAuthenticationToken unauthenticated(Object principal, Object credentials) {
		return new UsernamePasswordAuthenticationToken(principal, credentials);
	}

	/**
	 * This factory method can be safely used by any code that wishes to create a
	 * authenticated UsernamePasswordAuthenticationToken.
	 *
	 */
	public static UsernamePasswordAuthenticationToken authenticated(Object principal, Object credentials,
			Collection&lt;? extends GrantedAuthority&gt; authorities) {
		return new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
	}
}

If a developer leverages the Spring Security implementation of the AuthenticationManager -- the ProviderManager --, and of the AuthenticationProvider -- which for the username-password style of authentication is the DaoAuthenticationProvider --, they can rest assured that the user's credentials will be erased anyways before the authentication is set into the SecurityContextHolder. The ProviderManager class invokes the eraseCredentials() method, from the CredentialsContainer functional interface, to erase the credentials from the authenticated token.

I highly recommend that you use what the Spring Security team has already implemented, as their implementations were already tested and proven to be secure.

If you want to know more about the Spring Security Authentication Architecture, you can take a look into this page of the Spring Security reference documentation.

huangapple
  • 本文由 发表于 2023年4月20日 04:42:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058653.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定