Registered User
Registered User

Reputation: 2299

Spring Security: How to get details from the principal?

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

Answers (3)

Mike Glabay
Mike Glabay

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

Mario Rojas
Mario Rojas

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

Deadron
Deadron

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

Related Questions