spring security oauth2认证服务器 用户授权确认 流程源码 配置要点

2021-12-07 16:07:39 浏览数 (1)

源码

org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint

代码语言:javascript复制
// 授权
@RequestMapping(value = "/oauth/authorize")
public ModelAndView authorize(Map<String, Object> model, @RequestParam Map<String, String> parameters,
		SessionStatus sessionStatus, Principal principal) {
	...
	try {
		// 判断当前会话是否存在认证信息
		if (!(principal instanceof Authentication) || !((Authentication) principal).isAuthenticated()) {
			throw new InsufficientAuthenticationException(
					"User must be authenticated with Spring Security before authorization can be completed.");
		}
		// 校验请求中的scope是否包含在client中
		oauth2RequestValidator.validateScope(authorizationRequest, client);
		// TokenStoreUserApprovalHandler判断client是否存在autoApprove,并从tokenStore获取保存的approval信息,如果存在则将approved置为true
		authorizationRequest = userApprovalHandler.checkForPreApproval(authorizationRequest,
				(Authentication) principal);
		boolean approved = userApprovalHandler.isApproved(authorizationRequest, (Authentication) principal);
		authorizationRequest.setApproved(approved);
		// 如果已经存在用户授权,则直接授权
		if (authorizationRequest.isApproved()) {
			if (responseTypes.contains("token")) {
				return getImplicitGrantResponse(authorizationRequest);
			}
			if (responseTypes.contains("code")) {
				return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
						(Authentication) principal));
			}
		}
		// 将授权请求信息保存在session中以供后续用户确认时使用
		model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
		// 将授权请求原始信息保存在session中以供后续用户确认时使用
		model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, unmodifiableMap(authorizationRequest));
		// 不存在用户授权则跳转到用户确认页面
		return getUserApprovalPageResponse(model, authorizationRequest, (Authentication) principal);

	}
	...
}
// 用户授权确认页面确认后调用
@RequestMapping(value = "/oauth/authorize", method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL)
public View approveOrDeny(@RequestParam Map<String, String> approvalParameters, Map<String, ?> model,
		SessionStatus sessionStatus, Principal principal) {
	// 从会话中取出授权请求信息
	AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get(AUTHORIZATION_REQUEST_ATTR_NAME);

	if (authorizationRequest == null) {
		sessionStatus.setComplete();
		throw new InvalidRequestException("Cannot approve uninitialized authorization request.");
	}

	// 取出会话的授权请求信息以及原始授权请求信息,判断是否不一致
	@SuppressWarnings("unchecked")
	Map<String, Object> originalAuthorizationRequest = (Map<String, Object>) model.get(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME);
	if (isAuthorizationRequestModified(authorizationRequest, originalAuthorizationRequest)) {
		throw new InvalidRequestException("Changes were detected from the original authorization request.");
	}
	try {
		Set<String> responseTypes = authorizationRequest.getResponseTypes();
		// 根据用户提交的授权认可信息重新设置授权请求参数
		authorizationRequest.setApprovalParameters(approvalParameters);
		// 更新授权请求的确认标识,如果使用的是ApprovalStoreUserApprovalHandler/TokenStoreUserApprovalHandler或其他自定义handler,可在此处保存确认信息,以供后续授权请求自动确认。如果使用DefaultUserApprovalHandler则不进行保存
		authorizationRequest = userApprovalHandler.updateAfterApproval(authorizationRequest,
				(Authentication) principal);
		boolean approved = userApprovalHandler.isApproved(authorizationRequest, (Authentication) principal);
		authorizationRequest.setApproved(approved);
		// 如果用户拒绝授权,则跳转到错误信息页面
		if (!authorizationRequest.isApproved()) {
			RedirectView redirectView = new RedirectView(getUnsuccessfulRedirect(authorizationRequest,
					new UserDeniedAuthorizationException("User denied access"), responseTypes.contains("token")),
					false, true, false);
			redirectView.setStatusCode(HttpStatus.SEE_OTHER);
			return redirectView;
		}
		// 执行授权
		if (responseTypes.contains("token")) {
			return getImplicitGrantResponse(authorizationRequest).getView();
		}

		return getAuthorizationCodeResponse(authorizationRequest, (Authentication) principal);
	}
	...
}

用户授权认可处理默认配置

org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer

代码语言:javascript复制
// 默认的用户确认处理器
private UserApprovalHandler userApprovalHandler() {
	if (userApprovalHandler == null) {
		if (approvalStore() != null) {
			ApprovalStoreUserApprovalHandler handler = new ApprovalStoreUserApprovalHandler();
			handler.setApprovalStore(approvalStore());
			handler.setRequestFactory(requestFactory());
			handler.setClientDetailsService(clientDetailsService);
			this.userApprovalHandler = handler;
		}
		else if (tokenStore() != null) {
			TokenStoreUserApprovalHandler userApprovalHandler = new TokenStoreUserApprovalHandler();
			userApprovalHandler.setTokenStore(tokenStore());
			userApprovalHandler.setClientDetailsService(clientDetailsService());
			userApprovalHandler.setRequestFactory(requestFactory());
			this.userApprovalHandler = userApprovalHandler;
		}
		else {
			throw new IllegalStateException("Either a TokenStore or an ApprovalStore must be provided");
		}
	}
	return this.userApprovalHandler;
}
// 默认的确认仓库
private ApprovalStore approvalStore() {
	if (approvalStore == null && tokenStore() != null && !isApprovalStoreDisabled()) {
		TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
		tokenApprovalStore.setTokenStore(tokenStore());
		this.approvalStore = tokenApprovalStore;
	}
	return this.approvalStore;
}
// 默认的令牌仓库
private TokenStore tokenStore() {
	if (tokenStore == null) {
		if (accessTokenConverter() instanceof JwtAccessTokenConverter) {
			this.tokenStore = new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
		}
		else {
			this.tokenStore = new InMemoryTokenStore();
		}
	}
	return this.tokenStore;
}

自定义配置

实现org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter

代码语言:javascript复制
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.authenticationManager(authenticationManager);
    // 配置令牌仓库
    endpoints.tokenStore(redisTokenStore);
    // 不需要存储用户授权确认信息,则配置DefaultUserApprovalHandler
    endpoints.userApprovalHandler(new DefaultUserApprovalHandler());
    // 如不需要存储用户授权确认信息,配置此项
    endpoints.approvalStoreDisabled();
}
  • 注:如果配置了approvalStoreDisabled,必须配置userApprovalHandler,否则将报异常:

Either a TokenStore or an ApprovalStore must be provided

0 人点赞