SpringSecurityOAuth2多个第三方登录配置
继上一篇对使用第三方登录有了初体验后,这篇继续学习,这篇要做的很简单,就是配置多个第三方登录,上一篇用来Github,这次咱们加上Gitee看看是不是操作完全都一样。
使用OAuth2的授权码模式
1. 环境搭建
环境搭建部分与上一篇保持一致,复制下模块,更改下名字。
然后主要更改是在配置文件
2. 开始动手
- 增加多一个Gitee的授权登录
关于gitee中创建应用的就不多啰嗦了,可以自己在设置中找找,或者直接百度
按照之前的做法,咱们先在application.yaml中配置gitee,可能会这样子配置:
spring:
security:
oauth2:
client:
registration:
github:
clientId: xxxx # 填入自己应用的clientId
clientSecret: xxxxx # 填入自己应用的clientSecret
redirectUri: http://localhost:8844/login/oauth2/code/github
gitee:
clientId: xxxx # 填入自己应用的clientId
clientSecret: xxxxx # 填入自己应用的clientSecret
redirectUri: http://localhost:8844/login/oauth2/code/gitee
- 直接启动运行程序
这时会发现启动失败,报错了:
大概理解意思就是提供商gitee的id并没有指定,一脸懵,为啥GitHub的就完全没问题,gitee就不行呢?
这是因为SpringSecurity默认配置好了GitHub的Provider信息,而Gitee的没有,因此找不到Gitee的,我们可以看看官网的说明
这里说的很清楚了:SpringSecurity的OAuth2有一个CommonOAuth2Provider
预定义了几个比较知名的提供商:Google,Github,Facebook,Okta,因此对于这几个提供商,可以只配置clientId
和clientSecret
.
咱们可以看看这个CommonOAuth2Provider
源码:
public enum CommonOAuth2Provider {
GOOGLE {
public Builder getBuilder(String registrationId) {
Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
builder.scope(new String[]{"openid", "profile", "email"});
builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
builder.issuerUri("https://accounts.google.com");
builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
builder.userNameAttributeName("sub");
builder.clientName("Google");
return builder;
}
},
GITHUB {
public Builder getBuilder(String registrationId) {
Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
builder.scope(new String[]{"read:user"});
builder.authorizationUri("https://github.com/login/oauth/authorize");
builder.tokenUri("https://github.com/login/oauth/access_token");
builder.userInfoUri("https://api.github.com/user");
builder.userNameAttributeName("id");
builder.clientName("GitHub");
return builder;
}
},
FACEBOOK {
public Builder getBuilder(String registrationId) {
Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_POST, "{baseUrl}/{action}/oauth2/code/{registrationId}");
builder.scope(new String[]{"public_profile", "email"});
builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth");
builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token");
builder.userInfoUri("https://graph.facebook.com/me?fields=id,name,email");
builder.userNameAttributeName("id");
builder.clientName("Facebook");
return builder;
}
},
OKTA {
public Builder getBuilder(String registrationId) {
Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
builder.scope(new String[]{"openid", "profile", "email"});
builder.userNameAttributeName("sub");
builder.clientName("Okta");
return builder;
}
};
private static final String DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}";
private CommonOAuth2Provider() {
}
protected final Builder getBuilder(String registrationId, ClientAuthenticationMethod method, String redirectUri) {
Builder builder = ClientRegistration.withRegistrationId(registrationId);
builder.clientAuthenticationMethod(method);
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
builder.redirectUri(redirectUri);
return builder;
}
public abstract Builder getBuilder(String registrationId);
}
可以看到这就是一个枚举,里面定义好了提供商需要提供的一些信息,比如scope,authorizationUri,tokenUri,userInfoUri,userNameAttributeName,clientName
关于这些属性的作用可以这样理解:
- scope: 类似于权限
- authorizationUri:认证的url
- tokenUri: 获取access_token的url
- userInfoUri: 获取用户信息的url
- userNameAttributeName: 用户信息中用户名的属性名称
- clientName: 客户端名称
接着继续看官网,肯定有教我们如何自定义的:
- 完善配置
- 首先得先找到gitee的OAuth文档,以及userinfo结构
- 根据文档内容,将Provider所需要的数据填充上
spring:
security:
oauth2:
client:
registration:
github:
clientId: xxxx # 填入自己应用的clientId
clientSecret: xxxxx # 填入自己应用的clientSecret
redirectUri: http://localhost:8844/login/oauth2/code/github
gitee:
clientId: xxxx # 填入自己应用的clientId
clientSecret: xxxxx # 填入自己应用的clientSecret
redirectUri: http://localhost:8844/login/oauth2/code/gitee
authorizationGrantType: authorization_code
provider:
gitee:
authorizationUri: https://gitee.com/oauth/authorize
tokenUri: https://gitee.com/oauth/token
userInfoUri: https://gitee.com/api/v5/user
userNameAttribute: name
注意这里配置Gitee时还需要提供
authorizationGrantType
,我们用的是授权码模式,因此写上authorization_code
- 运行测试
-
访问本地
http://localhost:8844/hello
, 会展示多个登录选择,这里是github和gitee
-
点击gitee,会跳转到gitee的登录页面,之后都跟之前一样了,就不啰嗦了。
3. 扩展
前面我们访问的路径都是/hello
,只是返回一个"Hello World"的字符串,主打一个简单粗暴。
但是一般我们第三方登录其实要的就是用户信息,那我们怎么拿到这个信息?talk is cheap,show me the code
@GetMapping("/user")
public Map<String, Object> hello(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Map<String, Object> map = new HashMap<>(2);
map.put("oauth2client", oAuth2AuthorizedClient);
map.put("authentication", authentication);
return map;
}
通过加上注解
@RegisteredOAuth2AuthorizedClient
就可以拿到已经授权登录成功的用户信息了
4. 总结
通过这一篇文章,我了解到了原来配置其他的第三方登录,是需要自己提供Provider的,还有如何获取到已经授权登录的用户信息。
下一篇就来学习下源码,走下源码流程,看看具体是个怎么回事。
最后为把代码都上传到Github了,如果觉得有用,帮帮忙点个Start。
我的Github