简体   繁体   English

在 Spring 引导中处理 OAuth2 回调

[英]Handle OAuth2 callback in Spring Boot

I am trying to build a Spring Boot project with requires being signed into an OAuth2 SSO.我正在尝试构建一个需要登录到 OAuth2 SSO 的 Spring 引导项目。 I have the following Maven dependencies:我有以下 Maven 依赖项:

org.springframework.boot:spring-boot-starter-web
org.springframework.security:spring-security-oauth2-client
org.springframework.security:spring-security-config

I use HttpSecurity to enforce OAuth2 authentication for the app, using the following:我使用HttpSecurity为应用程序强制执行 OAuth2 身份验证,使用以下内容:

@EnableWebSecurity
@Order(101)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatcher("/api/auth/oauth2/callback").permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2Login();
    }

}

Now, what this does is: it sees that the user is not logged in, redirects them to the SSO, and after they have signed in it redirects the user back to the /api/auth/oauth2/callback?code=...&state=... endpoint.现在,它的作用是:它看到用户未登录,将他们重定向到 SSO,并在他们登录后将用户重定向回/api/auth/oauth2/callback?code=...&state=...端点。 That all works fine.这一切都很好。 However, I am fairly new to Spring Boot and I don't understand how I persist the fact the user is now authenticated (I know I still need to validate the callback, that's not a problem).但是,我对 Spring Boot 还很陌生,我不明白我如何坚持用户现在已通过身份验证的事实(我知道我仍然需要验证回调,这不是问题)。

Here is the authentication model that I would like to implement: I want to generate a hash within the callback endpoint, and store that hash in-memory within the app, and as a cookie on the user's browser.这是我想要实现的身份验证 model:我想在回调端点内生成 hash,并将 hash 存储在应用程序中的内存中,并作为用户浏览器中的 cookie。 Then, in any subsequent requests, the app would read that cookie's value, find the row in the in-memory database with the hash in it and grab the corresponding user data from the database row.然后,在任何后续请求中,应用程序将读取该 cookie 的值,在内存数据库中找到包含 hash 的行,并从数据库行中获取相应的用户数据。

I have looked extensively for a good example of this, however, all of the Spring Boot based OAuth2 examples use Github/Google OAuth and it seems to handle a lot of stuff under the hood (or perhaps I'm not understanding those properly).我已经广泛地寻找了一个很好的例子,但是,所有基于 Spring 引导的 OAuth2 示例都使用 Github/Google OAuth 并且它似乎在引擎盖下处理了很多东西(或者我可能没有正确理解这些东西)。

Any help/guidance would be greatly appreciated!任何帮助/指导将不胜感激!

In case it helps, here is my application.yml file:如果有帮助,这是我的application.yml文件:

spring:
  security:
    oauth2:
      client:
        registration:
          custom_sso_name:
            clientId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
            clientSecret: SUPER_SECRET
            authorizationGrantType: authorization_code
            redirectUri: https://dev.localhost/api/auth/oauth2/callback
        provider:
          custom_sso_name:
            userInfoUri: https://sso.example.com/nidp/oauth/nam/userinfo
            authorizationUri: https://sso.example.com/nidp/oauth/nam/authz
            tokenUri: https://sso.example.com/nidp/oauth/nam/token
            preferTokenInfo: false

You can check the Authentication Provider .您可以检查Authentication Provider

When you have set this, you can autowire the custom AuthenticationProvider and login a user in your controller whith SecurityContext like this:设置后,您可以自动装配自定义 AuthenticationProvider 并在 controller 中使用SecurityContext登录用户,如下所示:

    SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(new UserInfo(yourHash, token, expirationDate)));

Here, UserInfo is an example class (which extends AbstractAuthenticationToken ) that can hold the hash that you want to save, as any other data you may need.在这里, UserInfo 是一个示例 class (它扩展了AbstractAuthenticationToken ),它可以保存您想要保存的 hash 以及您可能需要的任何其他数据。

In the example of the above link they use UsernamePasswordAuthenticationToken , which may me enough to you if you only want to store a hash.在上面链接的示例中,他们使用UsernamePasswordAuthenticationToken ,如果您只想存储 hash,这对您来说可能已经足够了。 If you want to store extra info I would sugest to use a custom AuthenticationToken as it is UserInfo:如果你想存储额外的信息,我建议使用自定义的AuthenticationToken ,因为它是 UserInfo:

public class UserInfo extends AbstractAuthenticationToken {


    private String hash;
    private String oAuthToken;
    private DateTime expirationTime;

    public UserInfo (String hash, String oAuthToken, DateTime expirationTime){
        super(Collections.emptyList());
        this.hash= hash;
        this.oAuthToken = oAuthToken;
        this.expirationTime = expirationTime;
    }

    @Override
    public String getCredentials() {
       if(expirationTime.isAfter(DateTime.now())){
           return oAuthToken;
       } else {
           return null;
       }
    }

    @Override
    public String getPrincipal() {
        return hash;  //Or anything you stored that may be useful for checking the authentication
    }

Then, in any subsequent requests, the app would read that cookie's value, find the row in the in-memory database with the hash in it and grab the corresponding user data from the database row.然后,在任何后续请求中,应用程序将读取该 cookie 的值,在内存数据库中找到包含 hash 的行,并从数据库行中获取相应的用户数据。

After this authentication is finished, you can customly check authentication in any request:完成此身份验证后,您可以在任何请求中自定义检查身份验证:

@GetMapping("/")
public String profileSettings(Principal principal) {

    if (principal instanceof UserInfo){
        String hash = ((UserInfo) principal).getPrincipal();
       //Now you can use the hash for your custom logic, such like database reading
       return "profileSettings";
    } else {
       return "login";
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM