Reputation: 2299
Using spring boot and spring security, the details of user are available in principal object. But it has only few methods to retrieve details, like getName()
.
How do I get other details out of it?
Currently my class looks like this
@SpringBootApplication
@RestController
public class DemoOAuth2Application {
@RequestMapping("/user")
public Principal user(Principal principal) {
return principal;
}
public static void main(String[] args) {
SpringApplication.run(DemoOAuth2Application.class, args);
}
}
It returns this,
{
"authorities": [
{
"authority": "ROLE_USER"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "43Fxxxxxx",
"tokenValue": "ya29.xxxxxxxxx",
"tokenType": "Bearer",
"decodedDetails": null
},
"authenticated": true,
"userAuthentication": {
"authorities": [
{
"authority": "ROLE_USER"
}
],
"details": {
"id": "106xxxxx",
"email": "[email protected]",
"verified_email": true,
"name": "xxxx yyyyyy",
"given_name": "xxxxxx",
"family_name": "yyyyy",
"link": "https://plus.google.com/xxxxxxxxxx",
"picture": "https://lh5.googleusercontent.com/xxxxxx/photo.jpg",
"locale": "en"
},
"authenticated": true,
"principal": "106xxxxx",
"credentials": "N/A",
"name": "106xxxxxxx"
},
"principal": "106xxxxxxxxxxx",
"clientOnly": false,
"credentials": "",
"oauth2Request": {
"clientId": "xxxxxxxxx.apps.googleusercontent.com",
"scope": [],
"requestParameters": {},
"resourceIds": [],
"authorities": [],
"approved": true,
"refresh": false,
"redirectUri": null,
"responseTypes": [],
"extensions": {},
"refreshTokenRequest": null,
"grantType": null
},
"name": "106xxxxxxxxxx"
}
But instead of returning all the data, I'd like to return only specific data I need. How do I get that data(specifically email, name, link, picture).
Upvotes: 4
Views: 8432
Reputation: 21
For the Dev searching a similar thing... I had an issue writing my Discord login feature and I was high and low on Google...
So using some of the posts from here I propose my solution to you below.
@GetMapping("/profile")
public String getProfilePage(Principal principal, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// If the user requesting this page, is not an anonymous user
if (!(authentication instanceof AnonymousAuthenticationToken)) {
// parse the user for some basic information
parseAuthorizedUser(authentication);
return "profile";
}
}
The parseAuthorizedUser was taken from one of the above answers and utilizing Simple Json
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
I was able to take the authentication and, in my case, loop over the authorities, and for each of the OAuth2UserAuthority I make sure I'm checking my user role, and then breaking the authorities into a JSON Object, before then selecting just the attributes of the authority, and mapping it to a JSON Object as well. Then I just assurer it's not null or empty... and finally just set some atomicRefs I am using elsewhere
private void parseAuthorizedUser(Authentication authentication) {
// ... some previous code for profile basics
authentication.getAuthorities().forEach(oAuth2UserAuthority -> {
if (Objects.equals("ROLE_USER", oAuth2UserAuthority.getAuthority())) {
try {
String jsonAttributes = JsonUtil.getObjectAsJson(oAuth2UserAuthority);
JSONObject jsonObject = (JSONObject) new JSONParser().parse(jsonAttributes);
if (Objects.nonNull(jsonObject)) {
JSONObject userAttributes = (JSONObject) jsonObject.get("attributes");
if (Objects.nonNull(userAttributes) && !userAttributes.isEmpty()) {
discordId.set(userAttributes.get("id").toString());
discordAvatar.set(userAttributes.get("avatar").toString());
}
}
} catch (JsonProcessingException | ParseException e) {
throw new RuntimeException(e);
}
}
});
// ... continue on with the rest of the method
}
As for the mention of JsonUtil.getObjectAsJson(Object)
This is the method I use
public static String getObjectAsJson(Object object) throws JsonProcessingException {
return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(object);
}
It's a vague idea that may point you along the right path.
Upvotes: 0
Reputation: 1453
import org.springframework.security.oauth2.provider.OAuth2Authentication;
@SpringBootApplication
@RestController
public class DemoOAuth2Application {
@RequestMapping("/user")
public Authentication user(OAuth2Authentication authentication) {
LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) authentication.getUserAuthentication().getDetails();
return properties.get("email");
}
public static void main(String[] args) {
SpringApplication.run(DemoOAuth2Application.class, args);
}
}
Upvotes: 5
Reputation: 5289
Create a new object representing the subset of data you want to be returned from the endpoint. Then copy the data from the principal to the new object and finally return the new object.
Upvotes: 0