Spinrg Security原理 ------OAuth原理(二)

关于spring security ouath 中/oauth/authorize请求

配置autoApprove

clients.inMemory()
			.withClient("gz")
			.secret("{noop}gz123")
			.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
			.redirectUris("http://localhost:8084/login")
			.scopes("all").autoApprove("all")

AuthorizationEndpoint

首先进行clientDetail信息校验,查看是否有权限不经过确认页面直接跳转,如果autoApprove包含传递参数中Scope的参数,则不需要确认页面直接跳转,否则跳转到确认页面,点击授权,才能重定向

具体确认页面请看WhitelabelApprovalEndpoint类

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

		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_id,client_scret...
			ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId());

			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);

			oauth2RequestValidator.validateScope(authorizationRequest, client);
			// 查看是否有权限不经过确认页面直接跳转,否则跳转到确认页面,确认页面WhitelabelApprovalEndpoint,
			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));
				}
			}

			model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
			model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, unmodifiableMap(authorizationRequest));

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

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

	}

checkForPreApproval

是否不经过确认页面具体逻辑代码
1、查询clientDetail中存在的配置的autoApprove是否包含请求中的scope,包含则进行处理(如在JdbcApprovalStore中则会刷新approval然后新增approval信息),返回approval为true
2、查询approval列表,和请求中的scope做对照

public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
			Authentication userAuthentication) {

		String clientId = authorizationRequest.getClientId();
		Collection<String> requestedScopes = authorizationRequest.getScope();
		Set<String> approvedScopes = new HashSet<String>();
		Set<String> validUserApprovedScopes = new HashSet<String>();

		if (clientDetailsService != null) {
			try {
				// 查询clientDetail中存在的scope是否包含请求中的scope
				ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
				for (String scope : requestedScopes) {
					if (client.isAutoApprove(scope)) {
						approvedScopes.add(scope);
					}
				}
				if (approvedScopes.containsAll(requestedScopes)) {
					// gh-877 - if all scopes are auto approved, approvals still need to be added to the approval store.
					Set<Approval> approvals = new HashSet<Approval>();
					Date expiry = computeExpiry();
					for (String approvedScope : approvedScopes) {
						approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
								approvedScope, expiry, ApprovalStatus.APPROVED));
					}
					approvalStore.addApprovals(approvals);

					authorizationRequest.setApproved(true);
					return authorizationRequest;
				}
			}
			catch (ClientRegistrationException e) {
				logger.warn("Client registration problem prevent autoapproval check for client=" + clientId);
			}
		}

		if (logger.isDebugEnabled()) {
			StringBuilder builder = new StringBuilder("Looking up user approved authorizations for ");
			builder.append("client_id=" + clientId);
			builder.append(" and username=" + userAuthentication.getName());
			logger.debug(builder.toString());
		}

		// 查询approval列表,和请求中的scope做对照
		// Find the stored approvals for that user and client
		Collection<Approval> userApprovals = approvalStore.getApprovals(userAuthentication.getName(), clientId);

		// Look at the scopes and see if they have expired
		Date today = new Date();
		for (Approval approval : userApprovals) {
			if (approval.getExpiresAt().after(today)) {
				if (approval.getStatus() == ApprovalStatus.APPROVED) {
					validUserApprovedScopes.add(approval.getScope());
					approvedScopes.add(approval.getScope());
				}
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Valid user approved/denied scopes are " + validUserApprovedScopes);
		}

		// If the requested scopes have already been acted upon by the user,
		// this request is approved
		if (validUserApprovedScopes.containsAll(requestedScopes)) {
			approvedScopes.retainAll(requestedScopes);
			// Set only the scopes that have been approved by the user
			authorizationRequest.setScope(approvedScopes);
			authorizationRequest.setApproved(true);
		}

		return authorizationRequest;

	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值