如何保存使用OAuth 2(Spring)登录的用户?

问题描述 投票:5回答:3

我的主要目标是在用google登录后存储每个用户的客户端ID。这个github repo包含了我现在需要的大部分内容。关注的两个主要文件是OAuthSecurityConfig.javaUserRestController.java

当我导航到/user时,Principal包含我需要的所有详细信息。因此,我可以使用以下代码段来获取我需要的数据:

Authentication a = SecurityContextHolder.getContext().getAuthentication();
String clientId = ((OAuth2Authentication) a).getOAuth2Request().getClientId();

然后我可以将clientId存储在repo中

User user = new User(clientId);
userRepository.save(user);

这个问题是用户不必导航到/user。因此,人们可以在没有注册的情况下导航到/score/user1

这个API将来是一个Android应用程序的后端,所以jquery重定向到/user将是不安全的,不会工作。


我尝试过的事情:

尝试1

我创建了以下类:

@Service
public class CustomUserDetailsService implements UserDetailsService {

private final UserRepository userRepository;

@Autowired
public CustomUserDetailsService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = userRepository.findByUsername(username);
    if (user == null) {
        throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
    }
    return new UserRepositoryUserDetails(user);
}
}

并覆盖WebSecurityConfigurerAdapterwith:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(customUserDetailsService);
}

当用户登录时,不会调用两个重写的方法(我使用System.out.println检查)


尝试2

我尝试添加.userDetailsService(customUserDetailsService)

至:

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
            // Starts authorizing configurations.
            .authorizeRequests()
            // Do not require auth for the "/" and "/index.html" URLs
            .antMatchers("/", "/**.html", "/**.js").permitAll()
            // Authenticate all remaining URLs.
            .anyRequest().fullyAuthenticated()
            .and()
            .userDetailsService(customUserDetailsService)
            // Setting the logout URL "/logout" - default logout URL.
            .logout()
            // After successful logout the application will redirect to "/" path.
            .logoutSuccessUrl("/")
            .permitAll()
            .and()
            // Setting the filter for the URL "/google/login".
            .addFilterAt(filter(), BasicAuthenticationFilter.class)
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

这两种方法仍然没有调用,我觉得我更接近解决方案。任何帮助将不胜感激。

java spring spring-mvc spring-security oauth
3个回答
0
投票

如果有其他人坚持这个,我的解决方案是创建一个从OAuth2ClientAuthenticationProcessingFilter扩展的自定义类,然后覆盖successfulAuthentication方法以获取用户身份验证详细信息并将其保存到我的数据库。

示例(kotlin):

在你的ssoFilter方法(如果你按照本教程qazxsw poi)或任何你用来注册你的ouath客户端,改变使用

https://spring.io/guides/tutorials/spring-boot-oauth2

为您的自定义类

val googleFilter = Auth2ClientAuthenticationProcessingFilter("/login/google");

当然还要声明CustomAuthProcessingFilter类

val googleFilter = CustomAuthProcessingFilter("login/google")

0
投票

这里的方法是提供自定义OidcUserService并覆盖loadUser()方法,因为Google登录基于OpenId Connect。

首先定义一个模型类来保存提取的数据,如下所示:

class CustomAuthProcessingFilter(defaultFilterProcessesUrl: String?)
    : OAuth2ClientAuthenticationProcessingFilter(defaultFilterProcessesUrl) {

    override fun successfulAuthentication(request: HttpServletRequest?, response: HttpServletResponse?, chain: FilterChain?, authResult: Authentication?) {
        super.successfulAuthentication(request, response, chain, authResult)
        // Check if user is authenticated.
        if (authResult === null || !authResult.isAuthenticated) {
            return
        }

        // Use userDetails to grab the values you need like socialId, email, userName, etc...
        val userDetails: LinkedHashMap<*, *> = userAuthentication.details as LinkedHashMap<*, *>
    }
}

然后使用loadUser()方法创建自定义OidcUserService,该方法首先调用提供的框架实现,然后添加自己的逻辑以持久保存所需的用户数据,如下所示:

public class GoogleUserInfo {

    private Map<String, Object> attributes;

    public GoogleUserInfo(Map<String, Object> attributes) {
        this.attributes = attributes;
    }

    public String getId() {
        return (String) attributes.get("sub");
    }

    public String getName() {
        return (String) attributes.get("name");
    }

    public String getEmail() {
        return (String) attributes.get("email");
    }
}

并在安全配置类中注册自定义OidcUserService:

@Service
public class CustomOidcUserService extends OidcUserService {

    @Autowired
    private UserRepository userRepository; 

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        OidcUser oidcUser = super.loadUser(userRequest);

        try {
             return processOidcUser(userRequest, oidcUser);
        } catch (Exception ex) {
            throw new InternalAuthenticationServiceException(ex.getMessage(), ex.getCause());
        }
    }

     private OidcUser processOidcUser(OidcUserRequest userRequest, OidcUser oidcUser) {
        GoogleUserInfo googleUserInfo = new GoogleUserInfo(oidcUser.getAttributes());

        // see what other data from userRequest or oidcUser you need

        Optional<User> userOptional = userRepository.findByEmail(googleUserInfo.getEmail());
        if (!userOptional.isPresent()) {
            User user = new User();
            user.setEmail(googleUserInfo.getEmail());
            user.setName(googleUserInfo.getName());

           // set other needed data

            userRepository.save(user);
        }   

        return oidcUser;
    }
}

模式详细说明可以在文档中找到:

@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomOidcUserService customOidcUserService; @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login() .userInfoEndpoint() .oidcUserService(customOidcUserService); } }


© www.soinside.com 2019 - 2024. All rights reserved.