大家做第三方登录的客户端开发大多都是按照官网的文档来开发,没有走OAuth2 client的机制,其实这样的弊端很明显,官网提供的第三方登录的文档都是js调用,那就会过分暴露用户的资料,如果是一个前台项目(商城前台,游戏前台等等)还可以原谅,但是如果是一个后台管理的项目,那就很危险了。
我司是对技术要求极其严格的公司,肯定不允许这样不安全的开发存在。故我是用的Spirng Security OAuth2来实现了第三方的接入,我实现了facebook,google,github的第三方登录。而且还进行了授权。
我简单描述一下OAuth2的机制:OAuth协议被广泛应用于第三方授权登录中,用户可以通过第三方登录来使用该网站,能免去用户注册的麻烦,用户体验更佳。OAuth2定义了五种角色。客户端(Client)用户代理(User Agent)资源所有者(Resource Owner)授权服务器(Authorization Server)资源服务器(Resource Server)。OAuth协议已定义了4种授权模式,其中最具代表性的就是授权码模式,Spring Security OAuth2就是参用的这种模式。
整个授权流程说明如下(具体参数释义见下文):
客户端携带client_id, scope, redirect_uri, state等信息引导用户请求授权服务器的授权端点下发code
授权服务器验证客户端身份,验证通过则询问用户是否同意授权(此时会跳转到用户能够直观看到的授权页面,等待用户点击确认授权)
假设用户同意授权,此时授权服务器会将code和state(如果客户端传递了该参数)拼接在redirect_uri后面,以302形式下发code
客户端携带code, redirect_uri, 以及client_secret请求授权服务器的令牌端点下发access_token(这一步实际上中间经过了客户端的服务器,除了code,其它参数都是在应用服务器端添加,下文会细讲)
授权服务器验证客户端身份,同时验证code,以及redirect_uri是否与请求code时相同,验证通过后下发access_token,并选择性下发refresh_token
请求参数说明:
名称 | 是否必须 | 描述信息 |
---|---|---|
response_type | 必须 | 对于授权码模式response_type=code |
client_id | 必须 | 客户端ID,用于标识一个客户端,等同于appId,在注册应用时生成 |
redirect_uri | 可选 | 授权回调地址,具体参见2.2.3小节 |
scope | 可选 | 权限范围,用于对客户端的权限进行控制,如果客户端没有传递该参数,那么服务器则以该应用的所有权限代替 |
state | 推荐 | 用于维持请求和回调过程中的状态,防止CSRF攻击,服务器不对该参数做任何处理,如果客户端携带了该参数,则服务器在响应时原封不动的返回 |
对于OAuth协议不太熟悉的朋友,可以查看该位仁兄的文章:http://www.zhenchao.org/2017/03/04/oauth-v2-principle/
OAuth2.0协议的书籍:https://tools.ietf.org/html/rfc6749
大家搞明白了原理,接下来就是使用Spring Security OAuth2(后面会发现,Spring Security OAuth2是通过filer机制来解决OAuth协议认证授权的)来解决企业问题:
我的项目是maven项目使用的Spring Boot项目,首先是jar包依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
然后是官网资源的配置这一步比较简单:在官网进行项目的配置 下面是官网的链接(请先注册登录https://github.com/)
https://github.com/settings/applications/new
注:github支持http://localhost:8080的站点,
然后是java config配置:
HttpSecurity类:进行权限的配置,具体哪里路径可以直接放行.antMatchers(…).permitAll()
哪些路径需要权限认证 .antMatchers(…).hasAutority(…) 仅测试需要
.anyRequest().authenticated()
配置登录页面,登录错误页面 以及安全退出,安全退出页面,记住我等等。
ClientResources:资源所有者
包括:AuthorizationCodeResourceDetails有GrantType(授权机制"authorization_code"),preEstablishedRedirectUri,userAuthorizationUri,clientd,clientSecret,scope,authorizationScheme,tokenName等属性。
ResourceServerProperties:Configuration properties for OAuth2 Resources.及:从配置文件获取信息的bean对象 资源 。包含:clientId clientSecret userInfoUri tokenInfoUri属性。
OAuth2ClientContextFilter:OAuth2客户端的安全认证过滤器 所有请求的路径uri校验
UserInfoTokenServices:需要自定义实现,提供用户信息REST服务,默认的实现不能进行授权处理,
需要重写loadAuthentication方法,从数据库加载用户权限信息,如果不重写该方法,所有的通过第三方登录的用户都将只有ROLE_USER的权限,显然不能满足企业需要。
下面是所有的java config的配置信息。
ps:这可是我一点点总结的配置,望大家珍惜。
@EnableOAuth2Client
@EnableAuthorizationServer
@Order(6)
public class SocialApplication extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**","/js/**","/css/**","/hello").permitAll()
.antMatchers("/hello").hasAuthority("ROLE_USER")
.anyRequest().authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and().logout()
.logoutSuccessUrl("/").permitAll().and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
// @formatter:on
}
@Bean
@ConfigurationProperties("github")
public ClientResources github() {
return new ClientResources();
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(github(), "/login/github"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
client.getClient().getClientId());
tokenServices.setRestTemplate(oAuth2RestTemplate);
oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
return oAuth2ClientAuthenticationFilter;
}
}
class ClientResources {
@NestedConfigurationProperty
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
@NestedConfigurationProperty
private ResourceServerProperties resource = new ResourceServerProperties();
public AuthorizationCodeResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
做完了java config的配置,还需要配置application.yml文件,
github:
client:
clientId: bd1c0a783ccdd1c9b9e4
clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
accessTokenUri: https://github.com/login/oauth/access_token
userAuthorizationUri: https://github.com/login/oauth/authorize
clientAuthenticationScheme: form
resource:
userInfoUri: https://api.github.com/user
接下来就是官网图标的渲染,我是从官网扒下来的html
<!-- Github按钮 -->
<div>
<a href="/login/github">
<svg aria-hidden="true" class="octicon octicon-mark-github"
height="32" version="1.1" viewBox="0 0 16 16" width="32">
<path fill-rule="evenodd"
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z">
</path></svg>
</a>
</div>
到这里就大功告成了,大家可以启动自己的项目爽一把了。哈哈,我第一次看到github的第三方登录页面的时候超级开心,哈哈,大家也会和我一样很开心的。相同的机制,我也做了facebook,google的第三方登录很容易的。有哪里不太明白的地方可以留言,随时可以回答各位。
如果大家对Spring Security感兴趣,可以查看我的博客:
http://blog.csdn.net/weixin_38024391/article/details/71404582