If you need it implemented within Jmix application then you have to make changes according to the following example.
Setup Google OAuth client ID
https://support.google.com/cloud/answer/6158849?hl=en
Use http://localhost:8080/login/oauth2/code/google
as Authorized redirect URI.
Dependency
Add implementation 'org.springframework.security:spring-security-oauth2-client'
dependency.
Modify your User entity
Add field for Google ID
@Column(name = "GOOGLE_ID")
private String googleId;
Implement OidcUser and add Transient properties
@Transient
private OidcUserInfo userInfo;
@Transient
private OidcIdToken idToken;
@Transient
private Map<String, Object> attributes;
@Transient
private Map<String, Object> claims;
User mapping
Add service to load\store user based on Google ID
@Component
public class OAuth2UserPersistence {
@Autowired
private DataManager dataManager;
@Authenticated
public User loadUserByGoogleId(String googleId) {
return dataManager.load(User.class)
.query("select u from User u where u.googleId = :googleId")
.parameter("googleId", googleId)
.optional()
.orElseGet(() -> {
User user = dataManager.create(User.class);
user.setGoogleId(googleId);
return user;
});
}
@Authenticated
public User saveUser(User user) {
return dataManager.save(user);
}
}
Create/modify your security config to map external user to Jmix user
@EnableWebSecurity
@Configuration
public class OAuth2SecurityConfiguration extends FlowuiVaadinWebSecurity {
private static final Logger log = LoggerFactory.getLogger(OAuth2SecurityConfiguration.class);
private final RoleGrantedAuthorityUtils authorityUtils;
private final OAuth2UserPersistence oidcUserPersistence;
public OAuth2SecurityConfiguration(RoleGrantedAuthorityUtils authorityUtils,
OAuth2UserPersistence oidcUserPersistence) {
this.authorityUtils = authorityUtils;
this.oidcUserPersistence = oidcUserPersistence;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.oauth2Login(configurer ->
configurer
.loginPage(getLoginPath())
.userInfoEndpoint(userInfoEndpointConfig ->
userInfoEndpointConfig
.oidcUserService(oidcUserService()))
.successHandler(this::onAuthenticationSuccess)
);
}
private void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
// redirect to the main screen after successful authentication using auth provider
new DefaultRedirectStrategy().sendRedirect(request, response, "/");
}
/**
* Service responsible for loading OIDC users (Google uses OIDC protocol)
*/
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
//find or create user with given Google id
String googleId = oidcUser.getSubject();
User jmixUser = oidcUserPersistence.loadUserByGoogleId(googleId);
jmixUser.setUsername(googleId);
jmixUser.setGoogleId(googleId);
jmixUser.setEmail(oidcUser.getEmail());
User savedJmixUser = oidcUserPersistence.saveUser(jmixUser);
savedJmixUser.setAuthorities(getDefaultGrantedAuthorities());
return savedJmixUser;
};
}
/**
* Builds granted authority list that grants access to the FullAccess role
*/
private Collection<GrantedAuthority> getDefaultGrantedAuthorities() {
return List.of(authorityUtils.createResourceRoleGrantedAuthority(FullAccessRole.CODE));
}
}
UI
Add button to your login screen and in click\action handler execute
UI.getCurrent().getPage().setLocation("/oauth2/authorization/google");
Properties
Fill application properties
spring.security.oauth2.client.registration.google.client-id = <client id>
spring.security.oauth2.client.registration.google.client-secret = <client secret>
Regards,
Ivan