Skip to content

配置 hosts

shell
127.0.0.1 nacos
127.0.0.1 mysql
127.0.0.1 redis
127.0.0.1 kibana
127.0.0.1 rocketmq
127.0.0.1 admin.elsfs.test

启动oauth2

启动 Oauth2ApplicationStarter 注意: oauth2_registered_client数据库需要配置

sql
INSERT INTO oauth2_registered_client (id, client_id, client_id_issued_at, client_secret,
                                      client_secret_expires_at, client_name,
                                      client_authentication_methods, authorization_grant_types,
                                      redirect_uris, post_logout_redirect_uris, scopes, client_settings,
                                      token_settings)
VALUES ('5', 'messaging-client', '2023-12-02 18:48:22', '$2a$10$hVq5XfeMHERLoFo6RBUFieyrZF8ElwvRRgrig/wb/IkXUzz3zCZhG',
        null, '5', 'client_secret_basic', 'refresh_token,authorization_code',
        'http://admin.elsfs.test:7001/login/oauth2/code/login-client,http://127.0.0.1:7001/authorized,https://www.baidu.com',
        '', 'openid,profile,message.read,message.write',
        '{"@class":"java.util.Collections$UnmodifiableMap","settings.client.require-proof-key":false,"settings.client.require-authorization-consent":true}', '{
  "@class": "java.util.Collections$UnmodifiableMap",
  "settings.token.reuse-refresh-tokens": true,
  "settings.token.id-token-signature-algorithm": [
    "org.springframework.security.oauth2.jose.jws.SignatureAlgorithm",
    "RS256"
  ],
  "settings.token.access-token-time-to-live": [
    "java.time.Duration",
    3600.000000000
  ],
  "settings.token.access-token-format": {
    "@class": "org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat",
    "value": "self-contained"
  },
  "settings.token.refresh-token-time-to-live": [
    "java.time.Duration",
    3600.000000000
  ],
  "settings.token.authorization-code-time-to-live": [
    "java.time.Duration",
    300.000000000
  ],
  "settings.token.device-code-time-to-live": [
    "java.time.Duration",
    300.000000000
  ]
}');

elsfs-cloud-stater 配置文件新增如下配置 一定要和数据库一致,

提示

为什么使用 http://admin.elsfs.test:7002?如果两边都使用

yaml
spring:
  security:
    oauth2:
      client:
        registration:
          login-client:
            # http://127.0.0.1:7001/oauth2/authorization/login-client
            # 然后跳转到http://mysql:7002/login
            provider: spring
            client-id: messaging-client
            # "$2a$10$hVq5XfeMHERLoFo6RBUFieyrZF8ElwvRRgrig/wb/IkXUzz3zCZhG"
            client-secret: secret
            client-authentication-method: client_secret_basic
            authorization-grant-type: authorization_code
            redirect-uri: http://127.0.0.1:7001/login/oauth2/code/login-client
            scope:
              - openid
              - message.read
              - message.write
            client-name: spring
        provider:
          spring:
            user-name-attribute: sub
            token-uri: http://admin.elsfs.test:7002/oauth2/token
            user-info-uri: http://admin.elsfs.test:7002/userinfo
            authorization-uri: http://admin.elsfs.test:7002/oauth2/authorize
            jwk-set-uri: http://admin.elsfs.test:7002/oauth2/jwks

第一部: 访问: http://127.0.0.1:7001/oauth2/authorization/login-client 跳转到: http://admin.elsfs.test:7002/login

获取 code 后的 OAuth2LoginAuthenticationFilter 源码

java
public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {


    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        // 获取 code,state
        MultiValueMap<String, String> params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
        // 判断是否包含 code 和state
        if (!OAuth2AuthorizationResponseUtils.isAuthorizationResponse(params)) {
            OAuth2Error oauth2Error = new OAuth2Error("invalid_request");
            throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
        } else {
        // 删除授权请求
            OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository.removeAuthorizationRequest(request, response);
            if (authorizationRequest == null) {
                OAuth2Error oauth2Error = new OAuth2Error("authorization_request_not_found");
                throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
            } else {
            // 获取 注册 id login-client
                String registrationId = (String)authorizationRequest.getAttribute("registration_id");
                // 获取 客户端注册信息
                ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
                if (clientRegistration == null) {
                    OAuth2Error oauth2Error = new OAuth2Error("client_registration_not_found", "Client Registration not found with Id: " + registrationId, (String)null);
                    throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
                } else {
                    // 构建 重定向 url http://127.0.0.1:7001/login/oauth2/code/login-client
                    String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)).replaceQuery((String)null).build().toUriString();
                   // 构建授权响应
                    OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params, redirectUri);
                    Object authenticationDetails = this.authenticationDetailsSource.buildDetails(request);
                    // 通过 OidcAuthorizationCodeAuthenticationProvider 获取 OAuth2登录身份验证令牌
                    OAuth2LoginAuthenticationToken authenticationRequest = new OAuth2LoginAuthenticationToken(clientRegistration, new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
                    authenticationRequest.setDetails(authenticationDetails);
                    // 获取登录成功的 令牌
                    OAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken)this.getAuthenticationManager().authenticate(authenticationRequest);
                   // oauth2身份验证成功令牌
                    OAuth2AuthenticationToken oauth2Authentication = (OAuth2AuthenticationToken)this.authenticationResultConverter.convert(authenticationResult);
                    Assert.notNull(oauth2Authentication, "authentication result cannot be null");
                    oauth2Authentication.setDetails(authenticationDetails);
                    // 获取授权客户
                    OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(authenticationResult.getClientRegistration(), oauth2Authentication.getName(), authenticationResult.getAccessToken(), authenticationResult.getRefreshToken());
                    this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, oauth2Authentication, request, response);
                    return oauth2Authentication;
                }
            }
        }
    }
}

OidcAuthorizationCodeAuthenticationProvider 部分

java
public class OidcAuthorizationCodeAuthenticationProvider implements AuthenticationProvider {
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        OAuth2LoginAuthenticationToken authorizationCodeAuthentication = (OAuth2LoginAuthenticationToken)authentication;
        // 判断是否授权范围包含 openid
        if (!authorizationCodeAuthentication.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) {
            return null;
        } else {
        
            OAuth2AuthorizationRequest authorizationRequest = authorizationCodeAuthentication.getAuthorizationExchange().getAuthorizationRequest();
            OAuth2AuthorizationResponse authorizationResponse = authorizationCodeAuthentication.getAuthorizationExchange().getAuthorizationResponse();
            if (authorizationResponse.statusError()) {
                throw new OAuth2AuthenticationException(authorizationResponse.getError(), authorizationResponse.getError().toString());
           // 判断State是否一致
            } else if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
                OAuth2Error oauth2Error = new OAuth2Error("invalid_state_parameter");
                throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
            } else {
            // DefaultAuthorizationCodeTokenResponseClient ->getTokenResponse 获取 accessToken,refreshToken,和id_token
                OAuth2AccessTokenResponse accessTokenResponse = this.getResponse(authorizationCodeAuthentication);
                // 获取注册的客户端
                ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration();
                Map<String, Object> additionalParameters = accessTokenResponse.getAdditionalParameters();
                                //判断是否包含 id_token
                if (!additionalParameters.containsKey("id_token")) {
                    OAuth2Error invalidIdTokenError = new OAuth2Error("invalid_id_token", "Missing (required) ID Token in Token Response for Client Registration: " + clientRegistration.getRegistrationId(), (String)null);
                    throw new OAuth2AuthenticationException(invalidIdTokenError, invalidIdTokenError.toString());
                } else {
                // 通过jwtDecoder(jwt解码器)->OidcIdTokenDecoderFactory 创建Oidc令牌
                    OidcIdToken idToken = this.createOidcToken(clientRegistration, accessTokenResponse);
                    // 验证随机数 nonce ,nonce自行百度
                    this.validateNonce(authorizationRequest, idToken);
                    // 通过 OidcUserService 获取oidcUser
                    OidcUser oidcUser = (OidcUser)this.userService.loadUser(new OidcUserRequest(clientRegistration, accessTokenResponse.getAccessToken(), idToken, additionalParameters));
                   // 默认转换权限前面加“OIDC_”
                    Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper.mapAuthorities(oidcUser.getAuthorities());
                   // 设置验证成功
                    OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(authorizationCodeAuthentication.getClientRegistration(), authorizationCodeAuthentication.getAuthorizationExchange(), oidcUser, mappedAuthorities, accessTokenResponse.getAccessToken(), accessTokenResponse.getRefreshToken());
                    authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
                    return authenticationResult;
                }
            }
        }
    }


}

FederatedIdentityAuthenticationSuccessHandler

java
 @Override
  public void onAuthenticationSuccess(
      HttpServletRequest request, HttpServletResponse response, Authentication authentication)
      throws IOException, ServletException {
    if (authentication instanceof OAuth2AuthenticationToken auth2AuthenticationToken) {
    // 获取授权的名字
      String identifier = auth2AuthenticationToken.getName();
      // 授权的客户端名称
      String identityType = auth2AuthenticationToken.getAuthorizedClientRegistrationId();
      LOGGER.debug("oauth2Login登录成功,登录账号:{},登录类型:{}", identifier, identityType);
      // 断言是否要处理关联存储和绑定
      if (federatedIdentityPredicate.handlePredicate(identifier, identityType)) {
        registerLogicHandler.registerLogic(request, response, auth2AuthenticationToken);
        return;
      }
    }
    this.delegate.onAuthenticationSuccess(request, response, authentication);
  }

Last updated:

版权声明