大家上网的时候可能会遇见这样的一个问题,就是我们去访问一个网站,但是又不想去注册这个网站的账号,账号太多了实在是记不来,于是我们可以用qq或者微信登录这个网站,简直不要太方便有没有。
这么神奇的事情怎么能不去一探究竟呢,今天我们就来给他说道说道。
其实那些第三方服务他们都是使用了Oauth2.0这个协议,做的事情都是差不多,只是细节不同而已。
OAuth 是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前,OAuth 的最新版本为 2.0
OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth 允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容
OAuth 2.0定义了四种授权方式。
这里主要讲的是授权码模式,见下图
上图中所涉及到的对象分别为:
根据上图的信息,我们可以知道OAuth2的基本流程为:
好,我们了解了OAuth2.0之后,接下来介绍在spring boot2.0+security5环境下怎么实现Oauth2.0客户端第三方登录,这里我使用了github,其实qq,微信,微博那些都一样,都是基于OAuth2.0协议,只是国内这些还需要域名备案号这些信息罢了。
首先去github注册开发者应用,点击settings> Developer settings>OAuth app>new Oauth App,会看到下面的页面
org.springframework.security.oauth.boot
spring-security-oauth2-autoconfigure
2.0.0.RELEASE
#github新建app得到的id 和secret,这个需要填你自己配置的
github.client.clientId=a65cbf9654dfeb0d5142
github.client.clientSecret=5dd7327a494c4bea46b488a052fc1012dfbcc794
#获取token的地址
github.client.accessTokenUri=https://github.com/login/oauth/access_token
#登陆之后询问的地址
github.client.userAuthorizationUri=https://github.com/login/oauth/authorize
#2个Schema是指请求参数以什么样的方式跟随
github.client.authenticationScheme=query
github.client.clientAuthenticationScheme=form
#请求用户信息的url
github.client.resource.userInfoUri=https://api.github.com/user
安全配置上需要加上@EnableWebSecurity 、 @EnableOAuth2Client注解,来启用Web security Oauth2 客户端,表明这是一个OAuth 2.0 客户端
@EnableWebSecurity
@EnableOAuth2Client // 启用 OAuth 2.0 客户端
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//注入Oauth2.0客户端上下文
@Autowired
OAuth2ClientContext oauth2ClientContext;
注册两个bean获取配置文件自定义的内容,并返回相应的类
@Bean
@ConfigurationProperties("github.client")
public AuthorizationCodeResourceDetails github() {
return new AuthorizationCodeResourceDetails();
}
@Bean
@ConfigurationProperties("github.resource")
public ResourceServerProperties githubResource() {
return new ResourceServerProperties();
}
注册一个过滤器,用来截取code的回调地址,获取token
//自定义过滤器,用于拦截oauth2第三方登录返回code的url,并根据code,clientid,clientSecret去授权服务器拿accace_token
private Filter ssoFilter() {
//OAuth2ClientAuthenticationProcessingFilter
//它的构造器需要传入defaultFilterProcessesUrl,用于指定这个filter拦截哪个url。
//它依赖OAuth2RestTemplate来获取token
//还依赖ResourceServerTokenServices进行校验token
OAuth2ClientAuthenticationProcessingFilter githubFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/github");
//对rest template的封装,为获取token等提供便捷方法
//DefaultUserInfoRestTemplateFactory实例了OAuth2RestTemplate,这个提供了OAuth2RestTemplate
OAuth2RestTemplate githubTemplate = new OAuth2RestTemplate(github(), oauth2ClientContext);
githubFilter.setRestTemplate(githubTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(githubResource().getUserInfoUri(), github().getClientId());
tokenServices.setRestTemplate(githubTemplate);
githubFilter.setTokenServices(tokenServices);
return githubFilter;
}
注意这里的/login/github对应与在github填的Authorization callback URL。页面上使用github登录的链接也要写这个,security会帮我们做好一切流程
接下来需要注册我们的过滤器
/*注册一个额外的Filter:OAuth2ClientContextFilter
* 主要作用是重定向,当遇到需要权限的页面或URL,代码抛出异常,这时这个Filter将重定向到OAuth鉴权的地址
*/
@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
最后还有至关重要的一步,把自定义的过滤器添加到过滤器链中基本过滤器的前面
//在网站基本认证之前添加ssoFilter过滤器
http.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
如此这般,所有的工作就完成了
打开项目,点击页面上使用github登录的链接
点击授权之后
可以看到github的服务器给我们颁发了code,然后将页面重定向到我们配置的Homepage URL ,至此整个Oauth2.0的认证流程结束。
这里只要配置客户端,@EnableOAuth2Client就可以支持所有的社交平台,关键有一点,如果用户时第一次登陆,需要将用户信息注册到我们自己的数据库中,与数据库中的用户一一映射,就可以判断当前登陆的用户是对应我们数据库自己的平台身份。并且,Oauth2登陆时,我们将自定义的用户身份(也就是社交平台对应自己数据库的User)返回给security,进行登陆。这样就进行了用户绑定。这里主要实现了自定义的PrincipalExtractor接口,并非使用默认实现FixedPrincipalExtractor。参考这篇文章
这里就不贴我的代码了,放一下官网的demo,其实也一样
官方demo源码