весна: настройка точки авторизации (OAuth2) - PullRequest
0 голосов
/ 16 февраля 2020

Я пытаюсь настроить код сервера авторизации Spring oauth. сейчас я просто скопировал код авторизации FrameworkEndpoint и поместил его в другой класс. Я просто изменил сопоставление адресов на / custom / oauth / authorize. Я также добавил @Controller перед объявлением класса, иначе этот код вообще не будет использоваться:

@Controller
//@Order(Ordered.HIGHEST_PRECEDENCE)
@SessionAttributes("authorizationRequest")

public class AuthorizationEndpointCustom extends AuthorizationEndpoint {


    @Autowired
    private AuthenticationManager authenticationManager;

    private AuthorizationCodeServices authorizationCodeServices = new InMemoryAuthorizationCodeServices();

    private RedirectResolver redirectResolver = new DefaultRedirectResolver();

    private UserApprovalHandler userApprovalHandler = new DefaultUserApprovalHandler();

    private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();

    private OAuth2RequestValidator oauth2RequestValidator = new DefaultOAuth2RequestValidator();

    private String userApprovalPage = "forward:/oauth/confirm_access";

    private String errorPage = "forward:/oauth/error";

    private Object implicitLock = new Object();

    public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
        this.sessionAttributeStore = sessionAttributeStore;
    }

    public void setErrorPage(String errorPage) {
        this.errorPage = errorPage;
    }

    @RequestMapping(value = "/oauth/authorize")
    public ModelAndView authorize(Map<String, Object> model, @RequestParam Map<String, String> parameters,
            SessionStatus sessionStatus, Principal principal) {

        System.out.println("\n\ninside custom authorization endpoint");

        // Pull out the authorization request first, using the OAuth2RequestFactory. All further logic should
        // query off of the authorization request instead of referring back to the parameters map. The contents of the
        // parameters map will be stored without change in the AuthorizationRequest object once it is created.
        AuthorizationRequest authorizationRequest = getOAuth2RequestFactory().createAuthorizationRequest(parameters);

        Set<String> responseTypes = authorizationRequest.getResponseTypes();

        if (!responseTypes.contains("token") && !responseTypes.contains("code")) {
            throw new UnsupportedResponseTypeException("Unsupported response types: " + responseTypes);
        }

        if (authorizationRequest.getClientId() == null) {
            throw new InvalidClientException("A client id must be provided");
        }

        try {

            if (!(principal instanceof Authentication) || !((Authentication) principal).isAuthenticated()) {
                throw new InsufficientAuthenticationException(
                        "User must be authenticated with Spring Security before authorization can be completed.");
            }

            ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId());

            // The resolved redirect URI is either the redirect_uri from the parameters or the one from
            // clientDetails. Either way we need to store it on the AuthorizationRequest.
            String redirectUriParameter = authorizationRequest.getRequestParameters().get(OAuth2Utils.REDIRECT_URI);
            String resolvedRedirect = redirectResolver.resolveRedirect(redirectUriParameter, client);
            if (!StringUtils.hasText(resolvedRedirect)) {
                throw new RedirectMismatchException(
                        "A redirectUri must be either supplied or preconfigured in the ClientDetails");
            }
            authorizationRequest.setRedirectUri(resolvedRedirect);

            // We intentionally only validate the parameters requested by the client (ignoring any data that may have
            // been added to the request by the manager).
            oauth2RequestValidator.validateScope(authorizationRequest, client);

            // Some systems may allow for approval decisions to be remembered or approved by default. Check for
            // such logic here, and set the approved flag on the authorization request accordingly.
            authorizationRequest = userApprovalHandler.checkForPreApproval(authorizationRequest,
                    (Authentication) principal);
            // TODO: is this call necessary?
            boolean approved = userApprovalHandler.isApproved(authorizationRequest, (Authentication) principal);
            authorizationRequest.setApproved(approved);

            // Validation is all done, so we can check for auto approval...
            if (authorizationRequest.isApproved()) {
                if (responseTypes.contains("token")) {
                    return getImplicitGrantResponse(authorizationRequest);
                }
                if (responseTypes.contains("code")) {
                    return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
                            (Authentication) principal));
                }
            }

            // Place auth request into the model so that it is stored in the session
            // for approveOrDeny to use. That way we make sure that auth request comes from the session,
            // so any auth request parameters passed to approveOrDeny will be ignored and retrieved from the session.
            model.put("authorizationRequest", authorizationRequest);

            return getUserApprovalPageResponse(model, authorizationRequest, (Authentication) principal);

        }
        catch (RuntimeException e) {
            sessionStatus.setComplete();
            throw e;
        }

    }

    private OAuth2AccessToken getAccessTokenForImplicitGrant(TokenRequest tokenRequest,
            OAuth2Request storedOAuth2Request) {
        OAuth2AccessToken accessToken = null;
        // These 1 method calls have to be atomic, otherwise the ImplicitGrantService can have a race condition where
        // one thread removes the token request before another has a chance to redeem it.
        synchronized (this.implicitLock) {
            accessToken = getTokenGranter().grant("implicit",
                    new ImplicitTokenRequest(tokenRequest, storedOAuth2Request));
        }
        return accessToken;
    }


.
.
.

Я также дал указание каркасу изменить маппринг с / oauth / authorize на / custom / oauth / authorize:

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

    endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore())
            .accessTokenConverter(tokenEnhancer()).pathMapping("/oauth/authorize", "/custom/authorize/");
}

, но когда я запускаю код, я сталкиваюсь со следующей ошибкой:

Description:

Field tokenGranter in com.example.demo.controller.AuthorizationEndpointCustom required a bean of type 'org.springframework.security.oauth2.provider.TokenGranter' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.security.oauth2.provider.TokenGranter' in your configuration.

родительский класс AuthorizationEndpoint (AbstractEndpoint) объявляет tokenGranter, но он не создается. для этого и других атрибутов этого класса нет @autowired. кто генерирует и вводит эти переменные в этот класс? как мне получить tokenGranter obj и внедрить его?

/*
 * Copyright 2002-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.security.oauth2.provider.endpoint;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.util.Assert;

/**
 * @author Dave Syer
 * 
 */
public class AbstractEndpoint implements InitializingBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private WebResponseExceptionTranslator providerExceptionHandler = new DefaultWebResponseExceptionTranslator();

    private TokenGranter tokenGranter;

    private ClientDetailsService clientDetailsService;

    private OAuth2RequestFactory oAuth2RequestFactory;

    private OAuth2RequestFactory defaultOAuth2RequestFactory;

    public void afterPropertiesSet() throws Exception {
        Assert.state(tokenGranter != null, "TokenGranter must be provided");
        Assert.state(clientDetailsService != null, "ClientDetailsService must be provided");
        defaultOAuth2RequestFactory = new DefaultOAuth2RequestFactory(getClientDetailsService());
        if (oAuth2RequestFactory == null) {
            oAuth2RequestFactory = defaultOAuth2RequestFactory;
        }
    }

    public void setProviderExceptionHandler(WebResponseExceptionTranslator providerExceptionHandler) {
        this.providerExceptionHandler = providerExceptionHandler;
    }

    public void setTokenGranter(TokenGranter tokenGranter) {
        this.tokenGranter = tokenGranter;
    }

    protected TokenGranter getTokenGranter() {
        return tokenGranter;
    }

    protected WebResponseExceptionTranslator getExceptionTranslator() {
        return providerExceptionHandler;
    }

    protected OAuth2RequestFactory getOAuth2RequestFactory() {
        return oAuth2RequestFactory;
    }

    protected OAuth2RequestFactory getDefaultOAuth2RequestFactory() {
        return defaultOAuth2RequestFactory;
    }

    public void setOAuth2RequestFactory(OAuth2RequestFactory oAuth2RequestFactory) {
        this.oAuth2RequestFactory = oAuth2RequestFactory;
    }

    protected ClientDetailsService getClientDetailsService() {
        return clientDetailsService;
    }

    public void setClientDetailsService(ClientDetailsService clientDetailsService) {
        this.clientDetailsService = clientDetailsService;
    }

}

1 Ответ

0 голосов
/ 19 февраля 2020

Я отвечаю на свой вопрос. Я внимательно посмотрел на код платформы и обнаружил, что класс AuthorizationServerEndpointsConfiguration создает объект типа AuthorizationEndpoint и заполняет его атрибуты, а затем возвращает этот объект в виде компонента. Мне удалось решить вышеупомянутую проблему с TokenGranter путем создания компонента моего нового AuthorizationEndpointCustom таким же образом, как это делает AuthorizationServerEndpointsConfiguration. это код для этого:

@Autowired
private ClientDetailsService clientDetailsService;

@Autowired
AuthorizationServerEndpointsConfiguration asec;


@Bean
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Primary
public AuthorizationEndpoint authorizationEndpoint () throws Exception{

    AuthorizationEndpointCustom authorizationEndpoint = new AuthorizationEndpointCustom();
    FrameworkEndpointHandlerMapping mapping = asec.getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
    authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
    authorizationEndpoint.setProviderExceptionHandler(asec.getEndpointsConfigurer().getExceptionTranslator());
    authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
    authorizationEndpoint.setTokenGranter(asec.getEndpointsConfigurer().getTokenGranter());
    authorizationEndpoint.setClientDetailsService(clientDetailsService);
    authorizationEndpoint.setAuthorizationCodeServices(asec.getEndpointsConfigurer().getAuthorizationCodeServices());
    authorizationEndpoint.setOAuth2RequestFactory(asec.getEndpointsConfigurer().getOAuth2RequestFactory());
    authorizationEndpoint.setOAuth2RequestValidator(asec.getEndpointsConfigurer().getOAuth2RequestValidator());
    authorizationEndpoint.setUserApprovalHandler(asec.getEndpointsConfigurer().getUserApprovalHandler());

    return authorizationEndpoint;
}

private String extractPath(FrameworkEndpointHandlerMapping mapping, String page) {
    String path = mapping.getPath(page);
    if (path.contains(":")) {
        return path;
    }
    return "forward:" + path;
}

, но это не привело к тому, что я надеялся. новый компонент не заменяет компонент из кода платформы. эта ситуация с переопределением bean-компонентов привела к другому вопросу: как заменить bean-компоненты Framework

в нижней строке, это не способ переопределить конечные точки Framework. Вы можете просто создать контроллер с отображениями для этих конечных точек (например, / oauth / authorize или / oauth / token). автоматически эти отображения получат приоритет над конечными точками фреймворка. Для получения дополнительной информации см. Spring Do c

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...