繁体   English   中英

具有使用资源所有者密码凭证oauth流的多个客户端的中央身份验证服务器

[英]Central auth server with multiple clients using resource owner password credentials oauth flow

我进行了以下设置:

  • 使用Spring Boot编写的中央身份验证服务器当前正在运行(我可以卷曲并接收访问令牌,JDBC令牌存储等)
  • 同一开发人员拥有的多个应用程序,在不同的域上共享相同的客户群。 IE:app1的John Doe与app2的John Doe相同。

我有一个现成的应用程序(上面的app1)是jsf 2.2,并配置了用于登录目的的spring security。 该应用程序现在拥有自己的用户群,可以独立运行。

这是我尝试获取的流程: 资源所有者密码凭据OAuth流程

所以我们想要:

  1. 用户转到app1
  2. 用户在app1登录页面输入用户名和密码
  3. 用户点击“登录”
  4. 然后,Spring中的某种配置将接受loginByUsername请求,从中央oauth服务器获取访问令牌
  5. 现在,我们具有app1访问权限-用户可以具有三个角色之一(ADMIN,USER,SUPERUSER)。
  6. 当他们进入(例如)app1 / views / createEntry.xhtml时,我们将确认当前拥有的访问令牌在auth服务器上仍处于活动状态。
  7. 从技术上讲,资源服务器将是app1服务器上的资源(对吗?)

我是这个oauth2.0进程的新手(真的是spring),但是我认为这是我想要的流程。 如何使用Spring Security进行设置? 我已经看到了我们认为需要的名为oauth2login()的安全设置,但是我认为这是更多的授权代码流程。

使用密码流,我还没有找到一个很好的例子。

我确实信任此过程中的每个应用程序,因此密码流程也很可靠。 我们控制维护身份验证服务器和其他应用程序之间流量的网络。

编辑 :由于需求和我们的客户群的缘故,不能选择SSO。 这些应用程序足够独特,以至于毫无意义,但是用户应该能够使用这些凭据登录到我们的任何应用程序中。

编辑2 :对不起,第二次编辑。 我想补充一点,我已经在app1上添加了一个资源配置,并且看起来似乎可以正常工作-我已经保护了/ views / *的所有内容,并且当我尝试使用它们时,我得到了预期的“需要完整身份验证”消息。

编辑3 :我认为我正在取得一些进步-

首先,我创建了一个实现AuthenticationProvider的spring组件,然后重写了authenticate方法,以便创建具有我所有属性(客户端ID,客户端机密,授予类型,范围等)的ResourceOwnerPasswordResourceDetails对象,并调用授权服务器以获取令牌。 我很高兴看到授权服务器的日志刷新。

下一步,我需要弄清楚如何生成org.springframework.security.core.userdetails.User扩展,以便为用户存储特权。

另外-我还不太清楚令牌的存储方式。 我知道身份验证服务器会生成令牌并将其存储在jdbc中,但是令牌在哪里/如何存储在客户端?

对于那些好奇的人,这是我在客户端(app1)上设置身份验证提供程序的方式。 我仍然对资源服务器有问题(请问一个单独的问题),但这是我所做的:

定制验证器:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private AppUserDAO appUserDAO;

    private String accessTokenUri = "http://localhost:8080/oauth/token";
    private String clientId = "clientid";
    private String clientSecret = "clientsecret";

    public AccessTokenProvider userAccessTokenProvider() {
        ResourceOwnerPasswordAccessTokenProvider accessTokenProvider = new ResourceOwnerPasswordAccessTokenProvider();
        return accessTokenProvider;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        final String username = authentication.getName();
        final String password = authentication.getCredentials().toString();

        List<String> scopes = new ArrayList<String>();
        scopes.add("read");

        final ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

        resource.setUsername(username);
        resource.setPassword(password);
        resource.setAccessTokenUri(accessTokenUri);
        resource.setClientId(clientId);
        resource.setClientSecret(clientSecret);
        resource.setGrantType("password");
        resource.setScope(scopes);

        // Generate an access token
        final OAuth2RestTemplate template = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
        template.setAccessTokenProvider(userAccessTokenProvider());

        OAuth2AccessToken accessToken = null;

        try {
            accessToken = template.getAccessToken();
            System.out.println("Grabbed access token from " + accessTokenUri);
        }
        catch (OAuth2AccessDeniedException e) {
            if (e.getCause() instanceof ResourceAccessException) {
                final String errorMessage = String.format(
                        "While authenticating user '%s': " + "Unable to access accessTokenUri '%s'.", username,
                        accessTokenUri);
                throw new AuthenticationServiceException(errorMessage, e);
            }
            throw new BadCredentialsException(String.format("Access denied for user '%s'.", username), e);
        }
        catch (OAuth2Exception e) {
            throw new AuthenticationServiceException(
                    String.format("Unable to perform OAuth authentication for user '%s'.", username), e);
        }

        // Determine roles for user
        List<GrantedAuthority> grantList = ...

        // Create custom user for the principal
        User user = .....

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, null /*dont store password*/, grantList);

        return token;
    }

    @Override
    public  boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider authProvider;

    ....

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider);
    }   
}

暂无
暂无

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

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