Oauth 2---권한 수여 코드 모드(authorization코드 프로 세 스

17869 단어 자바
Oauth2--- 授权码模式(authorization_code)过程_第1张图片 Oauth2--- 授权码模式(authorization_code)过程_第2张图片
1.인증 코드 획득:
권한 수여 서버/oath/authorize 터미널 에 접근:("implicit","authorizationcode")
GET: http://127.0.0.1:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com
인자:
(1)response_type=code  반드시 지정 해 야 한다.
  (2) client_id=client  클 라 이언 트 가 지정 해 야 합 니 다.
(3)redirect_uri=http://주소 재 설정 은 데이터 시트 와 일치 해 야 합 니 다.
결과:권한 수여 에 동의 하면 code=cown 42 로 돌아 가 redirect 로 이동 합 니 다.uri=http://www.baidu.com
과정:비교 clientid,및 redirecturi、scope、
핵심 클래스 와 관련:
(1)DefaultRedirectResolver:redirect_uri 주소 검사.
(2)Jdbc Authorization Code Services/InMemory Authorization Code Services:생 성 된 code 를 메모리 나 데이터베이스(oauth코드 테이블
(3)JdbcClient Details Service:표 oauthclient_details 는 client Details 정 보 를 읽 어서 검사 합 니 다.
(4)LoginUrl Authentication Entry Point:마지막 로그 인 시 예외 적 으로 ExceptionTranslation Filter doFilter()-LoginUrl Authentication Entry Point->에서 loginFromUrl 페이지 로 재 설정 합 니 다.
 
public class AuthorizationEndpoint extends AbstractEndpoint {

// 、    :
	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";

// 、  :
@RequestMapping(value = "/oauth/authorize")
	public ModelAndView authorize(Map model, @RequestParam Map parameters,SessionStatus sessionStatus, Principal principal) {
 /*1.   DefaultOAuth2RequestFactory.createAuthorizationRequest()
    AuthorizationRequest request = new AuthorizationRequest();
 client      clietDetails  
   ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);		
	request.setResourceIdsAndAuthoritiesFromClientDetails(clientDetails);
*/		
AuthorizationRequest authorizationRequest = getOAuth2RequestFactory().createAuthorizationRequest(parameters);

		Set responseTypes = authorizationRequest.getResponseTypes();
        //2.       code
		if (!responseTypes.contains("token") && !responseTypes.contains("code")) {
			throw new UnsupportedResponseTypeException("Unsupported response types: " + responseTypes);
		}
        //3.    clientId
		if (authorizationRequest.getClientId() == null) {
			throw new InvalidClientException("A client id must be provided");
		}

		try {
            //4.         isAuthenticated = ture,    , ExceptionTranslationFilter doFilter()---》LoginUrlAuthenticationEntryPoint--》    loginFromUrl  。
			if (!(principal instanceof Authentication) || !((Authentication) principal).isAuthenticated()) {
				throw new InsufficientAuthenticationException(
						"User must be authenticated with Spring Security before authorization can be completed.");
			}
            //5.      clientDetails
			ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId());

			//6.     redirect_uri             。        :"implicit", "authorization_code"
			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);

			// 7。    Scope  
			oauth2RequestValidator.validateScope(authorizationRequest, client);

			// 8.    
			authorizationRequest = userApprovalHandler.checkForPreApproval(authorizationRequest,
					(Authentication) principal);
			// TODO: is this call necessary?
			boolean approved = userApprovalHandler.isApproved(authorizationRequest, (Authentication) principal);
			authorizationRequest.setApproved(approved);

			// 10.     ,      。
            // (1) Code  :  code,     InMemoryAuthorizationCodeServices(  ) JdbcAuthorizationCodeServices( oauth_code)
			if (authorizationRequest.isApproved()) {
				if (responseTypes.contains("token")) {
					return getImplicitGrantResponse(authorizationRequest);
				}
				if (responseTypes.contains("code")) {
					return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
							(Authentication) principal));
				}
			}

			//11.   ,     
			model.put("authorizationRequest", authorizationRequest);

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

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

	}

2.접근 토 큰 가 져 오기:권한 수여 서버/oauth/token 터미널 에 접근
사용자 가 로그 인 한 상태 인지 확인 하고 access 로 돌아 가기token 형식.
Post:
http://localhost:8080/oauth/token?
grant_type=authorization_code&code=o4YrCS&client_id=pair &client_secret=secret&redirect_uri=http://baidu.com

인자:
(1)clientId:클 라 이언 트 id,매개 변 수 를 지정 하 는 동시에 Principal 도 일치 해 야 합 니 다.그렇지 않 으 면 InvalidClient 예외(필수)
(2)client_secret:클 라 이언 트 밀 스푼
(2)grant_type:권한 부여 형식 입 니 다.(반드시
(3)코드:권한 수여 코드(필수)
핵심 클래스:
(1)AuthorizationServerTokenServices/DefaultTokenServices:이러한 종류 에서 token 을 생 성하 고 새로 고치 고 가 져 옵 니 다.
  (2)TokenStore:사용자 스스로 실현 코드 를 제공 합 니 다.
(3)클래스 포장 관계:AbstractEndpoint--->AuthorizationServerTokenServices(DefaultTokenServices)---TokenStore
@FrameworkEndpoint
public class TokenEndpoint extends AbstractEndpoint {

	private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();

    /**
    *   access_token
    **/
	@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
	public ResponseEntity postAccessToken(Principal principal, @RequestParam
	Map parameters) throws HttpRequestMethodNotSupportedException {
        //1.          ,       ,   ExceptionTranslationFilter doFilter()---》LoginUrlAuthenticationEntryPoint--》    loginFromUrl  。
		if (!(principal instanceof Authentication)) {
			throw new InsufficientAuthenticationException(
					"There is no client authentication. Try adding an appropriate authentication filter.");
		}
        //2.       ClientDetails  。
		String clientId = getClientId(principal);
		ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);

		TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
        //2.  clientId    
		if (clientId != null && !clientId.equals("")) {		
			if (!clientId.equals(tokenRequest.getClientId())) {
				throw new InvalidClientException("Given client ID does not match authenticated client");
			}
		}
        //3.  Scope
		if (authenticatedClient != null) {
			oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
		}
        //4.  GrantType:     implicit
		if (!StringUtils.hasText(tokenRequest.getGrantType())) {
			throw new InvalidRequestException("Missing grant type");
		}
		if (tokenRequest.getGrantType().equals("implicit")) {
			throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
		}
        //5.   authorization_code  ,  AuthCode:AuthCode != null && grant_type = authorization_code
		if (isAuthCodeRequest(parameters)) {
			// The scope was requested or determined during the authorization step
			if (!tokenRequest.getScope().isEmpty()) {
				logger.debug("Clearing scope of incoming token request");
				tokenRequest.setScope(Collections. emptySet());
			}
		}
        //      token: grant_type = refresh_token
		if (isRefreshTokenRequest(parameters)) {
			// A refresh token has its own default scopes, so we should ignore any added by the factory here.
			tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
		}
        //5.   token,TokenGranter(    )    OAuth2AccessToken。

		OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
		if (token == null) {
			throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
		}

		return getResponse(token);

	}
public abstract class AbstractTokenGranter implements TokenGranter {
	
    /**
    *    :  token      (   DefaultTokenServices       )
    **/
	private final AuthorizationServerTokenServices tokenServices;
	private final ClientDetailsService clientDetailsService;
	private final OAuth2RequestFactory requestFactory;
	private final String grantType;
}
OAuth2AccessToken {
   public static String BEARER_TYPE = "Bearer";
   public static String OAUTH2_TYPE = "OAuth2";
   public static String ACCESS_TOKEN = "access_token";
   public static String TOKEN_TYPE = "token_type";
   public static String EXPIRES_IN = "expires_in";
   public static String REFRESH_TOKEN = "refresh_token";
   public static String SCOPE = "scope";
}
/**
 * 1.TokenStore:   ,  token         
 * 2.    :(1)  accessToken    、     (2)loadAuthentication()accessToken        
 * 3.   :
 *   (1)AuthorizationServerTokenServices:        accessToken    、    。
 *   (2)ResourceServerTokenServices:        accessToken       ,         tokenString---> OAuth2Authentication
 */
public class DefaultTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,
        ConsumerTokenServices, InitializingBean {

    //Token  、    。(    )
    private TokenStore tokenStore;
    //ClientDetail   
    private ClientDetailsService clientDetailsService;
    //Token    
    private TokenEnhancer accessTokenEnhancer;
    //    : token   ,      
    private AuthenticationManager authenticationManager;

    /**
     *     OAuth2AccessToken
     */
    @Transactional
    public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {

        //1.    tokenStore    accessToken
        OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
        OAuth2RefreshToken refreshToken = null;
        //1.tokenStore accessToken ,      。
        if (existingAccessToken != null) {
            if (existingAccessToken.isExpired()) {
                if (existingAccessToken.getRefreshToken() != null) {
                    refreshToken = existingAccessToken.getRefreshToken();
                    tokenStore.removeRefreshToken(refreshToken);
                }
                tokenStore.removeAccessToken(existingAccessToken);
            }
            else {
                tokenStore.storeAccessToken(existingAccessToken, authentication);
                return existingAccessToken;
            }
        }

       //2.   accessToken   refreshToken    
        refreshToken = createRefreshToken(authentication);
        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        tokenStore.storeAccessToken(accessToken, authentication);
        tokenStore.storeRefreshToken(refreshToken, authentication);
        
        return accessToken;

    }

    /**
     *   aceessToken
     */
    @Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
    public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
            throws AuthenticationException {
        //1.   token
        OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
        //2.    
        OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
        //3.    、  token
        refreshToken = createRefreshToken(authentication);
        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        tokenStore.storeAccessToken(accessToken, authentication);
        tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
        
        return accessToken;
    }

    /**
     *  accessToken    OAuth2Authentication
     */
    public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,
            InvalidTokenException {
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
        OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
        //  
        if (clientDetailsService != null) {
            String clientId = result.getOAuth2Request().getClientId();
            try {
                clientDetailsService.loadClientByClientId(clientId);
            }
            catch (ClientRegistrationException e) {
                throw new InvalidTokenException("Client not valid: " + clientId, e);
            }
        }
        return result;
    }

    /**
     *   RefreshToken     json   
     */
    private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
        // OAuth2RefreshToken    : @JsonValue String getValue();
        return new DefaultOAuth2RefreshToken(value);
    }

    /**
     *    OAuth2AccessToken
     */
    private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
        //  AccessToken
        /**OAuth2AccessToken    
         private String value;
        private Date expiration;
        private String tokenType = BEARER_TYPE.toLowerCase();
        private OAuth2RefreshToken refreshToken;
        private Set scope;
        private Map additionalInformation = Collections.emptyMap();
        */
        
        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
        token.setRefreshToken(refreshToken);
        token.setScope(authentication.getOAuth2Request().getScope());
        //       accessTokenEnhancer      
        return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
    }

    
}

 
3.자원 서버 에 접근 하여 보 호 된 자원:
accesstoken 자원 가 져 오기,요청 헤더 에 토 큰 추가,**Bearer 추가**
방문
(1)PostMan 도구:GET/POST:/xxx/xxxx 헤더:Authorization Bearer accesstoken
(2)Curl 명령:curl-X GET\\http://localhost:9001/test \ -i -H "Accept: application/json" -H "Authorization: Bearer eyJhbG" \
 
4.AuthorizationServerEndpoints Configurer 설정:
주로 생각 하 는 ServerBean 을 주입 한다.
/**
	 *   token     
	 * 1.              AuthenticationManager
	 * 2.    AccessToken     tokenStore,             。
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

		TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
		endpoints
				.authenticationManager(authenticationManager)
				.userDetailsService(userDetailsService) //MUST:          AuthenticationManager  ,   UserDetails  
				.tokenStore(tokenStore)//token     
				.tokenEnhancer(tokenEnhancerChain);//token     
}

//  Endpoints              ,       
public final class AuthorizationServerEndpointsConfigurer {

	private AuthorizationServerTokenServices tokenServices;

	private ConsumerTokenServices consumerTokenServices;

	private AuthorizationCodeServices authorizationCodeServices;

	private ResourceServerTokenServices resourceTokenServices;

	private TokenStore tokenStore;

	private TokenEnhancer tokenEnhancer;

	private AccessTokenConverter accessTokenConverter;

	private ApprovalStore approvalStore;

	private TokenGranter tokenGranter;

	private OAuth2RequestFactory requestFactory;

	private OAuth2RequestValidator requestValidator;

	private UserApprovalHandler userApprovalHandler;

	private AuthenticationManager authenticationManager;

	private ClientDetailsService clientDetailsService;

	private String prefix;

	private Map patternMap = new HashMap();

	private Set allowedTokenEndpointRequestMethods = new HashSet();

	private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping;

	private boolean approvalStoreDisabled;

	private List interceptors = new ArrayList();

	private DefaultTokenServices defaultTokenServices;

	private UserDetailsService userDetailsService;

	private boolean tokenServicesOverride = false;

	private boolean userDetailsServiceOverride = false;

	private boolean reuseRefreshToken = true;

	private WebResponseExceptionTranslator exceptionTranslator;

	private RedirectResolver redirectResolver;
}

좋은 웹페이지 즐겨찾기