例如, 下面的代码展示了一个例子: @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .authorizationEndpoint() ... .redirectionEndpoint() ... .tokenEndpoint() ... .userInfoEndpoint() ... } }
OAuth 2.0 授权框架定义协议端点如下: 授权过程使用两个授权服务器端点(HTTP 资源):
以及一个客户端端点:
OpenID Connect Core 1.0 规范定义了用户信息端点如下: 用户信息端点是一个 OAuth 2.0 保护资源,它返回关于已验证的最终用户的声明。为了获得所请求的关于最终用户的声明,客户端通过使用通过 OpenID 连接认证获得的访问令牌向用户信息端点发出请求。这些声明通常由 JSON 对象表示,JSON 对象包含声明的 name-value 对集合。
下面的代码显示了 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .clientRegistrationRepository(this.clientRegistrationRepository()) .authorizedClientService(this.authorizedClientService()) .loginPage("/login") .authorizationEndpoint() .baseUri(this.authorizationRequestBaseUri()) .authorizationRequestRepository(this.authorizationRequestRepository()) .and() .redirectionEndpoint() .baseUri(this.authorizationResponseBaseUri()) .and() .tokenEndpoint() .accessTokenResponseClient(this.accessTokenResponseClient()) .and() .userInfoEndpoint() .userAuthoritiesMapper(this.userAuthoritiesMapper()) .userService(this.oauth2UserService()) .oidcUserService(this.oidcUserService()) .customUserType(GitHubOAuth2User.class, "github"); } } 下面的章节将详细介绍每个可用的配置选项:
默认情况下,OAuth 2.0 登录页是由 每个 OAuth Client 的链接的目的地默认为以下内容:
下面的行展示了一个例子: <a href="/oauth2/authorization/google">Google</a>
要覆盖默认登录页,配置 下面的列显示了一个示例: @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .loginPage("/login/oauth2") ... .authorizationEndpoint() .baseUri("/login/oauth2/authorization") .... } }
如果你想提供在 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .authorizationEndpoint() .authorizationRequestRepository(this.cookieAuthorizationRequestRepository()) ... } private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() { return new HttpCookieOAuth2AuthorizationRequestRepository(); } } 授权服务器使用 Redirection Endpoint 通过 Resource Owner 用户代理将授权响应(包含授权凭证)返回给客户端。
默认授权响应
如果你想自定义授权响应 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .redirectionEndpoint() .baseUri("/login/oauth2/callback/*") .... } }
如果你想提供使用 Spring Framework 5 的响应式 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .tokenEndpoint() .accessTokenResponseClient(this.accessTokenResponseClient()) ... } private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() { return new SpringWebClientAuthorizationCodeTokenResponseClient(); } } UserInfo Endpoint 包含若干配置选项,如以下子部分所述:
在用户成功地通过 OAuth 2.0 提供者进行认证之后,
当映射用户权限时,有两个选项可供选择:
提供 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .userAuthoritiesMapper(this.userAuthoritiesMapper()) ... } private GrantedAuthoritiesMapper userAuthoritiesMapper() { return (authorities) -> { Set<GrantedAuthority> mappedAuthorities = new HashSet<>(); authorities.forEach(authority -> { if (OidcUserAuthority.class.isInstance(authority)) { OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority; OidcIdToken idToken = oidcUserAuthority.getIdToken(); OidcUserInfo userInfo = oidcUserAuthority.getUserInfo(); // Map the claims found in idToken and/or userInfo // to one or more GrantedAuthority's and add it to mappedAuthorities } else if (OAuth2UserAuthority.class.isInstance(authority)) { OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority; Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes(); // Map the attributes found in userAttributes // to one or more GrantedAuthority's and add it to mappedAuthorities } }); return mappedAuthorities; }; } }
或者,可以注册 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.oauth2Login(); } @Bean public GrantedAuthoritiesMapper userAuthoritiesMapper() { ... } }
但是,与使用
下面的示例演示如何使用 OpenID Connect 1.0 UserService 实现和配置基于委托的策略: @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .oidcUserService(this.oidcUserService()) ... } private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() { final OidcUserService delegate = new OidcUserService(); return (userRequest) -> { // Delegate to the default implementation for loading a user OidcUser oidcUser = delegate.loadUser(userRequest); OAuth2AccessToken accessToken = userRequest.getAccessToken(); Set<GrantedAuthority> mappedAuthorities = new HashSet<>(); // TODO // 1) Fetch the authority information from the protected resource using accessToken // 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities // 3) Create a copy of oidcUser but use the mappedAuthorities instead oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo()); return oidcUser; }; } }
如果默认实现(
下面的代码演示了如何为 GitHub 注册自定义 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .customUserType(GitHubOAuth2User.class, "github") ... } }
下面的代码展示了为 GitHub 自定义 public class GitHubOAuth2User implements OAuth2User { private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); private Map<String, Object> attributes; private String id; private String name; private String login; private String email; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return this.authorities; } @Override public Map<String, Object> getAttributes() { if (this.attributes == null) { this.attributes = new HashMap<>(); this.attributes.put("id", this.getId()); this.attributes.put("name", this.getName()); this.attributes.put("login", this.getLogin()); this.attributes.put("email", this.getEmail()); } return attributes; } public String getId() { return this.id; } public void setId(String id) { this.id = id; } @Override public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String getLogin() { return this.login; } public void setLogin(String login) { this.login = login; } public String getEmail() { return this.email; } public void setEmail(String email) { this.email = email; } }
如果默认实现不适合你的需要,你可以为标准的 OAuth 2.0 提供程序定义自己的
下面的配置演示如何配置自定义的 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .userService(this.oauth2UserService()) ... } private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() { return new CustomOAuth2UserService(); } }
如果默认实现不适合你的需要,那么你可以定义自己的 OpenID Connect 1.0 Provider 的
下面的配置演示如何配置自定义 OpenID Connect 1.0 @EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .oidcUserService(this.oidcUserService()) ... } private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() { return new CustomOidcUserService(); } } |