问题
I created userinfo
endpoint in my authorization server.
@GetMapping("/userinfo")
public Principal me(Principal principal) {
return principal;
}
It returns this JSON:
{
...
"userAuthentication": {
...
"principal": {
"id": 2,
"username": "xyz",
"password": "......",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true,
"authorities": [
{
"authority": "ROLE_DONOR"
}
],
"createdAt": "2019-11-08T20:50:46"
},
...
"name": "xyz"
},
...
"principal": {
"id": 2,
"username": "xyz",
"password": "......",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true,
"authorities": [
{
"authority": "ROLE_DONOR"
}
],
"createdAt": "2019-11-08T20:50:46"
},
...
"name": "xyz"
}
In one of my Resource Servers, User Service API, I tried to sysout
the value of Principal
just to see its value:
@GetMapping("/{id}")
public ResourceResponseDto findById(@PathVariable("id") long id, Principal principal) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String x = objectMapper.writeValueAsString(principal);
System.out.println(x);
return ...;
}
The value of principal
is different. Its value is equivalent to above principal.username
, leaving out other fields:
{
"userAuthentication": {
...
"principal": "xyz",
...
"name": "xyz"
},
...
"principal": "xyz",
...
"name": "xyz"
}
How does that happen?
I need to get the value of id
but it's gone. The fields of principal
object are gone. That causes I think error for my other method:
@GetMapping("/{id}")
@PreAuthorize("hasRole('ADMIN') or #id == principal.id")
public ResourceResponseDto findById(@PathVariable("id") long id) {
//
}
I'm getting this error;
Failed to evaluate expression 'hasRole('ADMIN') or #id == principal.id'
Please help. Thanks.
回答1:
As I understand, you are implementing OAuth2 Spring Authentication Server.
Principle
is just an interface that declares the method getName()
. For authentication and resource servers principle
is implemented by the class OAuth2Authentication
. method getPrinciple()
:
public Object getPrincipal() {
return this.userAuthentication == null ? this.storedRequest.getClientId() : this.userAuthentication.getPrincipal();
}
If OAuth2 client is being authenticated, it does not have an userAuthentication
, just clientId
. If user is being authenticated, you see full userAuthentication
object.
回答2:
from the Authentication.getPrincipal()
documentation:
The identity of the principal being authenticated. In the case of an authentication request with username and password, this would be the username. Callers are expected to populate the principal for an authentication request. The AuthenticationManager implementation will often return an Authentication containing richer information as the principal for use by the application. Many of the authentication providers will create a UserDetails object as the principal.
So, you are in charge of populating the Principal
on the authentication process.
One of the way to pass additional info to the Principal
, is by extending the UsernamePasswordAuthenticationFilter
and overriding the 'attemptAuthentication()' method:
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) {
String username = obtainUsername(request);
String password = obtainPassword(request);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
setDetails(request, authRequest);
Authentication authenticated = this.getAuthenticationManager().authenticate(authRequest);
return new UsernamePasswordAuthenticationToken(
new YourObjectForPrincipal(...),
authenticated.getCredentials(), authenticated.getAuthorities());
}
Note passing the YourObjectForPrincipal
object, that could contain any data you want, as the first parameter to the UsernamePasswordAuthenticationToken
.
To get your extended user, just cast to the desired object:
(YourObjectForPrincipal)authentication.getPrincipal();
It's might be not the best solution, but it worked for me. I hope it will help.
来源:https://stackoverflow.com/questions/59391630/spring-security-principal-from-authorization-server-is-different-from-resource