八、社交登录-QQ登录-飞
发布时间: 2023-07-06
摘要

在做自己的产品时,为了更好的用户体验,在登录注册这一环节,我们现在越来越多的使用社交登录(QQ、微信、FB等)。为了规范社交账号登录出现OAuth协议。

一、OAuth

在我们使用一个第三方的APP(Client_App),点击使用社交应用登录时,首先会离开Client_App调到社交应用,在社交应用上会显示一个授权界面,点击确定授权后又会从社交应用调回到Client_App中并且登录成功。这个流程是用户最直接的感受,那么在技术层面有做了哪些事。OAuth授权.pngOAuth协议中的授权模式授权码模式(authorization code)简化模式(implicit)密码模式(resource owner password credentials)客户端模式(client credentials)二、SpringSecurity社交原理授权码模式流程.png
社交应用授权流程.png1.我们需要配置跳转到社交应用服务提供商的认证服务器url2.在社交应用服务提供商提供的界面进行授权3.社交应用服务提供商的认证服务器会生成授权码并且返回Client(第三方应用)4.Client(第三方应用)发送请求Token令牌的请求5.社交应用服务提供商中的认证服务器会把生成的Token令牌返回给Client(第三方应用)6.Client(第三方应用)携带Token令牌去社交服务提供商的资源服务器请求用户信息,并且返回给Client(第三方应用)7.通过用户信息构建Authentication,并放入SecurityContext三、SpringSecurity社交源码1、SocialAuthenticationFilter 过滤器
    // 默认拦截的请求url    private static final String DEFAULT_FILTER_PROCESSES_URL = "/auth";    // 默认注册url    private String signupUrl = "/signup";// 尝试认证用户private Authentication attemptAuthService(final SocialAuthenticationService<?> authService, final HttpServletRequest request, HttpServletResponse response)             throws SocialAuthenticationRedirectException, AuthenticationException {        final SocialAuthenticationToken token = authService.getAuthToken(request, response);        if (token == null) return null;                Assert.notNull(token.getConnection());                Authentication auth = getAuthentication();        if (auth == null || !auth.isAuthenticated()) {            return doAuthentication(authService, request, token);        } else {            addConnection(authService, request, token, auth);            return null;        }           }
2、OAuth2AuthenticationService
// 用来生成授权Token(SocialAuthenticationToken)public SocialAuthenticationToken getAuthToken(HttpServletRequest request, HttpServletResponse response) throws SocialAuthenticationRedirectException {        // 请求中是否携带【授权码】        String code = request.getParameter("code");        if (!StringUtils.hasText(code)) {            OAuth2Parameters params =  new OAuth2Parameters();            params.setRedirectUri(buildReturnToUrl(request));            setScope(request, params);            params.add("state", generateState(connectionFactory, request));            addCustomParameters(params);            // 跳转到授权界面            throw new SocialAuthenticationRedirectException(getConnectionFactory().getOAuthOperations().buildAuthenticateUrl(params));        } else if (StringUtils.hasText(code)) {            try {                // 回调地址                String returnToUrl = buildReturnToUrl(request);                // 获得accessToken                AccessGrant accessGrant = getConnectionFactory().getOAuthOperations().exchangeForAccess(code, returnToUrl, null);                // TODO avoid API call if possible (auth using token would be fine)                Connection<S> connection = getConnectionFactory().createConnection(accessGrant);                return new SocialAuthenticationToken(connection, null);            } catch (RestClientException e) {                logger.debug("failed to exchange for access", e);                return null;            }        } else {            return null;        }    }
3、OAuth2Connection<A>
public OAuth2Connection(String providerId, String providerUserId, String accessToken, String refreshToken, Long expireTime,            OAuth2ServiceProvider<A> serviceProvider, ApiAdapter<A> apiAdapter) {        super(apiAdapter);        this.serviceProvider = serviceProvider;        initAccessTokens(accessToken, refreshToken, expireTime);        initApi();        initApiProxy();        initKey(providerId, providerUserId);    }
4、AbstractConnection<A>
private ServiceProviderConnectionValuesImpl setValues() {        ServiceProviderConnectionValuesImpl values = new ServiceProviderConnectionValuesImpl();        apiAdapter.setConnectionValues(getApi(), values);        valuesInitialized = true;        ret

微信