I am using spring session for redis for my oauth2 login. I have implemented a custom principal.
@Data
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public final class CustomUserOidcPrincipal extends CustomUserPrincipal implements OidcUser {
@JsonIgnore
private String name;
@JsonIgnore
private Map<String, Object> claims;
@JsonIgnore
private OidcIdToken idToken;
@JsonIgnore
private OidcUserInfo userInfo;
@JsonIgnore
private Map<String, Object> attributes;
//oidc principal constructor..
public CustomUserOidcPrincipal(String id, String email, String password,
String username,
Boolean isOidcLogin,
Set<GrantedAuthority> roles,
Boolean mfaEnabled,
Boolean disabled, Boolean locked,
String name,
Map<String, Object> claims,
OidcIdToken idToken, OidcUserInfo userInfo,Map<String,Object> attributes
) {
super(id, email, password, username, isOidcLogin, roles, mfaEnabled, !disabled, !locked);
this.name = name;
this.claims = claims;
this.idToken = idToken;
this.userInfo = userInfo;
this.attributes = attributes;
}
@JsonIgnore
@Override
public Map<String, Object> getAttributes() {
return this.attributes;
}
@JsonIgnore
@Override
public String getName() {
return this.name;
}
@JsonIgnore
@Override
public Map<String, Object> getClaims() {
return this.claims;
}
@JsonIgnore
@Override
public OidcUserInfo getUserInfo() {
return this.userInfo;
}
@JsonIgnore
@Override
public OidcIdToken getIdToken() {
return this.idToken;
}
}
Now before using spring session I was using default httpSession, and the oauth2 login was working perfectly fine. But now the there is an issue, the fields which i have put @JsonIgnore is not getting serialized, but the attributes in that fields, like in OidcUserInfo, there are fields like email, familyName etc.., they are getting serialized. This is my serialized json.
{
"@class":"org.springframework.security.core.context.SecurityContextImpl",
"authentication":{
"@class":"org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken",
"principal":{
"@class":"com.test.mmt.configuration.security.authentication.principal.CustomUserOidcPrincipal",
"id":"01JWQSJ8GVQ8RVB1ERC9S4JY7G",
"email":"test@gmail.com",
"username":"test@gmail.com",
"isOidcLogin":true,
"authorities":[
"java.util.HashSet",
[
{
"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority",
"authority":"ROLE_USER"
},
{
"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority",
"authority":"ROLE_ADMIN"
}
]
],
"mfaEnabled":true,
"locked":false,
"isMfaAuthenticated":false,
"isAdminAuthenticated":false,
"nonce":"CilzMtqiAKIyaH35XemvykUQQmEKUXoa8JVGYXW8xx0",
"subject":"100812923335268714792",
"authenticationContextClass":null,
"authenticationMethods":null,
"authorizationCodeHash":null,
"authenticatedAt":null,
"authorizedParty":"101205211125502-6qs23n3dmq6xascaa.apps.googleusercontent.com",
"accessTokenHash":"xxxxx",
"audience":[
"java.util.ArrayList",
[
"10120211125502-6qsn3dmq6sd1ssxc34sxkddtos.apps.googleusercontent.com"
]
],
"issuedAt":"2025-06-12T12:05:56Z",
"expiresAt":"2025-06-12T13:05:56Z",
"givenName":"Allen",
"address":{
"@class":"org.springframework.security.oauth2.core.oidc.DefaultAddressStandardClaim",
"formatted":null,
"streetAddress":null,
"locality":null,
"region":null,
"postalCode":null,
"country":null
},
"locale":null,
"zoneInfo":null,
"fullName":"Allen Bastian",
"preferredUsername":null,
"emailVerified":true,
"phoneNumberVerified":null,
"familyName":"Bastian",
"middleName":null,
"nickName":null,
"picture":"https://random-c",
"website":null,
"gender":null,
"birthdate":null,
"phoneNumber":null,
"updatedAt":null,
"profile":null
},
"authorities":[
"java.util.Collections$UnmodifiableRandomAccessList",
[
{
"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority",
"authority":"ROLE_USER"
},
{
"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority",
"authority":"ROLE_ADMIN"
}
]
],
"authorizedClientRegistrationId":"01JWXSQ642SZC4V142Y3Z92DMS",
"details":{
"@class":"org.springframework.security.web.authentication.WebAuthenticationDetails",
"remoteAddress":"0:0:0:0:0:0:0:1",
"sessionId":"01JWQSHTR0KV0GGZSVC2PPATCE-b4f3196e-c25a-4673-9a36-0618dbfc2cfc"
}
}
}
When tried to deserialize it gets thrown this exception, (I tried without @JsonIgnoreProperties
) too.
org.springframework.data.redis.serializer.SerializationException: Could not read JSON:Problem deserializing 'setterless' property ("audience"): no way to handle typed deser with setterless yet
This is my redis serializer config (i am using seperate ObjectMapper for this case)
private ObjectMapper objectMapper() {
ObjectMapper mapper = this.mapper.copy();
mapper.addMixIn(CustomUserPrincipal.class,CustomUserPrincipalMixin.class);
mapper.addMixIn(CustomUserOidcPrincipal.class, CustomUserOidcPrincipalMixin.class);
mapper.addMixIn(HashSet.class, HashSetMixin.class);
mapper.registerModules(SecurityJackson2Modules.getModules(this.loader));
return mapper;
}
please help on this issue, i still dont get why every field is getting flatMapped when serialized.
So i fixed this problem by configuring objectmapper to use field only, instead of setters or getters.
private ObjectMapper objectMapper() {
ObjectMapper mapper = this.mapper.copy();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mapper.addMixIn(CustomUserPrincipal.class, CustomUserPrincipalMixin.class);
mapper.addMixIn(CustomOidcUserPrincipal.class, CustomOidcUserPrincipalMixin.class);
mapper.addMixIn(HashSet.class, HashSetMixin.class);
mapper.registerModules(SecurityJackson2Modules.getModules(this.loader));
return mapper;
}
So i guess the ObjectMapper was serializing based on OidcUser interface, and it called all the getters inside that also OidcIdToken
,OidcUserInfo
so on. If anyone can give a proper explanation on why this happened or give some reference, it would be appreciated.