OAuth协议是一个授权协议,目的是让用户在不将服务提供商的用户名密码交给第三方应用的条件下,让第三方应用可以有权限访问用户存在服务提供商上的资源。
接着上一篇说的,在第三方应用获取到用户资源后,如果过去的不是用户的自拍数据,而是用户的昵称头像等基本信息,根据这些基本信息,构建经过认证的Authentication对象,放进SecurityContext,这对于spring security来说,就算认证成功了。第三方应用引导用户走完这个流程,就是用户使用用户在服务提供商的上的用户基本信息登录了第三方应用。
图一
SpringSocial:就是把这个流程封装成了一个SocialAuthenticationFilter过滤器,然后吧这个过滤器加到springsecurity的过滤器链上。
官方定义:将您的Spring应用程序与软件即服务(SaaS)API提供程序(如Facebook,Twitter和LinkedIn)连接起来。
这样当你访问某一个请求的时候,SocialAuthenticationFilter会把这个请求拦截下来,然后走完上图的流程。这样就是实现了微信登录。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
附 :Spring Security对登录成功的定义
在处理登录过滤器的抽象类AbstractAuthenticationProcessingFilter定义了的doFilter方法定义了登录操作:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } if (logger.isDebugEnabled()) { logger.debug("Request is to process authentication"); } Authentication authResult; try { authResult = attemptAuthentication(request, response); if (authResult == null) { // return immediately as subclass has indicated that it hasn't completed // authentication return; } sessionStrategy.onAuthentication(authResult, request, response); } catch (InternalAuthenticationServiceException failed) { logger.error( "An internal error occurred while trying to authenticate the user.", failed); unsuccessfulAuthentication(request, response, failed); return; } catch (AuthenticationException failed) { // Authentication failed unsuccessfulAuthentication(request, response, failed); return; } // Authentication success if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authResult); }
其中的successfulAuthentication()方法定义了认证成功后的操作:
SecurityContextHolder.getContext().setAuthentication(authResult)这句话就是说,认证成功后,用SecurityContextHolder.getContext()获取到spring安全的上下文SecurityContext,往里边放一个认证类Authentication,这就算是登录成功了。
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); rememberMeServices.loginSuccess(request, response, authResult); // Fire event if (this.eventPublisher != null) { eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( authResult, this.getClass())); } successHandler.onAuthenticationSuccess(request, response, authResult); }
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Spring Social:
相关接口
图一中的步骤1~步骤6,都是在和服务提供商打交道
1,ServiceProvider:服务提供商的抽象,针对不同的服务提供商,如新浪、qq、微信,都需要一个ServiceProvider具体实现。
SpringSocial提供了AbstractOAuth2ServiceProvider抽象类,实现了共有的东西。我们使用时候继承这个类即可。
图一步中服务提供商中骤1~步骤5是OAuth标准的流程,第6步是个性化的。因为每一个服务提供商对的用户基本信息结构的定义都是不一样的。如字段的个数,名字可能都不一样。
OAuth2Operations:封装了第1步到第5步标准的OAuth协议的处理流程,Oauth2协议的相关的操作。这个接口Spring Social提供了一个默认的实现OAuth2Template。
Api:处理第6步需要的接口的实现,没有明确的接口,需要自定义,因为每个服务提供商对用户信息的调用都是有区别的。SpringSocial的默认实现是AbstractOAuth2Binding
2,Connection:用户信息的封装,命名是固定的,需要一个ApiAdapter适配器来转换api和connection。用来获取前6步获取到的用户信息,Spring Social的实现是OAuth2Connection,由ConnectionFactory工厂接口创建的(该工厂接口的默认实现是OAuth2ConnectionFactory,需要ServiceProvider),第7步是再第三方应用服务内部完成的。
3,UsersConnectionRepository:服务提供商里的用户和业务系统里的用户之间有对应关系,在spring social中是存在数据库中UserConnection表里,存储了业务中系统中User表的userid和服务提供商的用户(Connection)之间的对应关系。UsersConnectionRepository(默认实现是JdbcUsersConnectionRepository)来操作这个表