英文:
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
isnull
, it sets the authorities to an empty list usingList.of()
. - If
userDetails
is notnull
, it sets the authorities usinguserDetails.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<? 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' 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<? 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 into this page of the Spring Security reference documentation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论