簡體   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