第三方登录_QQ

1.QQ配置文件:


#第三方QQ登录配置
constants:
    # QQ
    qqAppId: ******(QQ平台的AppID)
    qqAppSecret: **********(QQ平台的AppSecret)
    qqRedirectUrl: ***********(登录成功后的回调路径:http://ucapi.****.com/api/v1/anon/qq_login)
    qqTokenUrl: https://graph.qq.com/oauth2.0/token?(QQtoken路径)
    qqUrl: https://graph.qq.com/oauth2.0/authorize?(QQ访问路径)
    clientId: ****-****-***-***-***** (客户端id)
    url: http://uc.***.com (跳转首页,注册页的路径域名)

2.QQ第三方登录:常量配置类

package com.ciip.cloud.core.usercenter.constants;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import javax.validation.constraints.NotEmpty;

/**
 * Title: ThirdLoginConstants
 * Description: 第三方QQ登录:常量配置类
 *
 * @author 
 * @created
 */
@Configuration
@ConfigurationProperties(prefix = "constants")
@Getter
@Setter
public class ThirdLoginConstants {

    /**
     *  QQ的AppID
     */
    @NotEmpty
    private String  qqAppId;

    /**
     * QQ的AppSecret
     */
    @NotEmpty
    private String qqAppSecret;

    /**
     * QQ的回调路径
     */
    @NotEmpty
    private String qqRedirectUrl;
    /**
     * QQtoken路径
     *          
     */
    @NotEmpty
    private String qqTokenUrl;
    /**
     * QQ访问路径
     *          
     */
    @NotEmpty
    private String qqUrl;
 /**
     * clientId
     *         
     */
    @NotEmpty
    private String clientId;
    /**
     * 域名路径
     *          
     */
    @NotEmpty
    private String url;

}

3.controller层:

package com.ciip.cloud.core.usercenter.controller;
/**
 * Title: ThirdLoginController
 * Description: 第三方QQ登录
 *
 * @author 
 * @created 
 */

import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.usercenter.service.QQAuthService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

@Api(value = "ThirdLoginController", description = "第三方登录(微信,QQ,微博)")
@RestController
@RequestMapping(value = CIIPCommonConstant.ApiPath.V1, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public class ThirdLoginController {


    @Autowired
    QQAuthService qqAuthService;


    /**
     * CIIP改版:QQ第三方登录页面
     *                  
     * @return
     */
    @GetMapping(value =  CIIPCommonConstant.ApiAuth.ANON +"/qq_loginUrl")
    public String getQQCode(){
        return  qqAuthService.getQQCode();
    }

    /**
     * CIIP改版:获取QQ登录后的token,openid等值
     *                 
     * @param code
     * @param response
     * @return
     */
    @PostMapping(value =  CIIPCommonConstant.ApiAuth.ANON +"/qq_accessToken")
    public String getQQAccessToken(String code,HttpServletResponse response){
       return qqAuthService.getQQAccessToken(code);
    }
}

4.service层:

package com.ciip.cloud.core.usercenter.service;


/**
 * Title: QQAuthService
 * Description: QQ 认证接口
 *
 * @author 
 * @created 2019/5/8 17:30
 */

public interface QQAuthService {

    /**
     *  CIIP 改版:获取 Code,即登陆页面的 URL
     *             
     *
     * @return
     */
    String getQQCode();

    /**
     *  CIIP 改版:获取token,该步骤返回的token期限为一个月
     *             
     * @return
     */
    String getQQAccessToken(String code);

    /**
     * CIIP 改版:根据accessToken,获取QQ的openId
     *             
     *
     * @param accessToken
     * @return
     */
    String getOpenId(String accessToken);
}

5.service实现层:

package com.ciip.cloud.core.usercenter.service.impl;

import com.ciip.cloud.core.usercenter.constants.ThirdLoginConstants;
import com.ciip.cloud.core.usercenter.model.CiipTokenLog;
import com.ciip.cloud.core.usercenter.service.CiipTokenLogService;
import com.ciip.cloud.core.usercenter.service.QQAuthService;
import com.ciip.cloud.core.usercenter.utils.HttpClientUtils;
import com.ciip.cloud.core.usercenter.utils.URLEncodeUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;


/**
 * Title: QQAuthServiceImpl
 * Description: TODO
 *
 * @author 
 * @created 
 */

@Service
public class QQAuthServiceImpl implements QQAuthService {


    @Autowired
    ThirdLoginConstants thirdLoginConstants;
    @Autowired
    CiipTokenLogService ciipTokenLogService;

    /**
     *获取 Code,即登陆页面的 URL
     *              
     *
     * @return
     */
    @Override
    public String getQQCode() {
        //拼接url
        StringBuilder url = new StringBuilder();
        //url.append("https://graph.qq.com/oauth2.0/authorize?");
        url.append(thirdLoginConstants.getQqUrl());
        url.append("response_type=code");
        url.append("&client_id=").append(thirdLoginConstants.getQqAppId());
        //回调地址 ,回调地址要进行Encode转码
        String redirect_uri = thirdLoginConstants.getQqRedirectUrl();
        //转码
        url.append("&redirect_uri=").append(URLEncodeUtil.getURLEncoderString(redirect_uri));
        url.append("&state=ok");
        System.out.println(url.toString());
        return  url.toString();
    }

    /**
     * 获取token,该步骤返回的token期限为一个月
     *              
     * @return
     */
    @Override
    public String getQQAccessToken(String code) {
        if("".equals(code)){
                return "code为空.";
        }
        StringBuilder url = new StringBuilder();
        //url.append("https://graph.qq.com/oauth2.0/token?");
        url.append(thirdLoginConstants.getQqTokenUrl());
        url.append("grant_type=authorization_code");
        url.append("&client_id=").append(thirdLoginConstants.getQqAppId());
        url.append("&client_secret=").append(thirdLoginConstants.getQqAppSecret());
        url.append("&code=").append(code);
        //回调地址
        String redirect_uri = thirdLoginConstants.getQqRedirectUrl();
        //转码
        url.append("&redirect_uri=").append(URLEncodeUtil.getURLEncoderString(redirect_uri));
        String result = null;
        try {
            result = HttpClientUtils.get(url.toString(),"UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("url:" + url.toString());
        //把token保存
        String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(result, "&");

        String accessToken = StringUtils.substringAfterLast(items[0], "=");
        Integer expiresIn = new Integer(StringUtils.substringAfterLast(items[1], "="));
        String refreshToken = StringUtils.substringAfterLast(items[2], "=");

        //获取openId
        String openId = this.getOpenId(accessToken);

        //token 信息的添加
        CiipTokenLog ciipTokenLog = new CiipTokenLog();

        ciipTokenLog.setAccessToken(accessToken);
        ciipTokenLog.setExpiresIn(expiresIn);
        ciipTokenLog.setRefreshToken(refreshToken);
        ciipTokenLog.setOpenId(openId);

        ciipTokenLogService.saveCiipTokenLog(ciipTokenLog);

        return openId;
    }

    /**
     * CIIP 改版:根据accessToken,获取QQ的openId
     *             
     *
     * @param accessToken
     * @return
     */
    @Override
    public String getOpenId(String accessToken) {
        StringBuilder url = new StringBuilder("https://graph.qq.com/oauth2.0/me?");
        //获取保存的用户的token
        if (!StringUtils.isNotEmpty(accessToken)){
            return "未授权";
        }
        url.append("access_token=").append(accessToken);
        String result = null;
        try {
            result = HttpClientUtils.get(url.toString(),"UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String openId = StringUtils.substringBetween(result, "\"openid\":\"", "\"}");
        System.out.println(openId);

        return openId;
    }
}

6.安全配置(SecurityConfig):

package com.ciip.cloud.core.usercenter.oauth;

import com.ciip.cloud.core.usercenter.handler.CustomAccessDeniedHandler;
import com.ciip.cloud.core.usercenter.oauth.moblie.SmsAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.moblie.SmsCodeFilter;
import com.ciip.cloud.core.usercenter.oauth.qq.QQCodeFilter;
import com.ciip.cloud.core.usercenter.oauth.qq.QqAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.weiBo.WeiBoAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.weiBo.WeiBoCodeFilter;
import com.ciip.cloud.core.usercenter.oauth.weiXin.WeiXinAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.weiXin.WeiXinCodeFilter;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    UserDetailsService userDetailsService;



    @Autowired
    CustomAccessDeniedHandler customAccessDeniedHandler;


    @Autowired
    private SmsAuthenticationConfig smsAuthenticationConfig;

    @Autowired
    private QqAuthenticationConfig qqAuthenticationConfig;
    @Autowired
    private WeiXinAuthenticationConfig weiXinAuthenticationConfig;
    @Autowired
    private WeiBoAuthenticationConfig weiBoAuthenticationConfig;
    @Autowired
    private SmsCodeFilter smsCodeFilter;
    @Autowired
    private WeiXinCodeFilter weiXinCodeFilter;
    @Autowired
    private WeiBoCodeFilter weiBoCodeFilter;
    @Autowired
    private QQCodeFilter qqCodeFilter;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception { // @formatter:off

        http
                // 头部缓存
                .headers()
                .cacheControl()
                .and()
                // 防止网站被人嵌套
                .frameOptions()
                .sameOrigin();

        http
                .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器
                .addFilterBefore(weiXinCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加weixin验证码校验过滤器
                .addFilterBefore(weiBoCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加weiBo验证码校验过滤器
                .addFilterBefore(qqCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加QQ验证码校验过滤器
                .formLogin().and()
                .authorizeRequests() // 授权配置
                .antMatchers("/login","/api/v1/anon/**","/oauth/authorize","/oauth/token").permitAll() // 无需认证的请求路径
                .and()
                .csrf().disable()
                .apply(smsAuthenticationConfig)//短信验证
                .and().apply(qqAuthenticationConfig) // 第三方QQ登录验证
                .and().apply(weiXinAuthenticationConfig) // 第三方WeiXin登录验证
                .and().apply(weiBoAuthenticationConfig); // 第三方微博登录验证



        http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);


    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { // @formatter:off
        auth.userDetailsService(userDetailsService).passwordEncoder(customPasswordEncoder());
    } // @formatter:on

    //TODO 为了符合原有BIM用户加密方式,所以自定义加密规则
    @Bean
    public PasswordEncoder customPasswordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return DigestUtils.md5Hex(rawPassword.toString());
            }
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return DigestUtils.md5Hex(rawPassword.toString()).equals(encodedPassword);
            }
        };
    }
    //TODO 采用内置加密方式,存储数据库格式如:'{MD5}e10adc3949ba59abbe56e057f20f883e'
    @Bean
    PasswordEncoder passwordEncoder(){
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

7.QQ身份验证配置:

package com.ciip.cloud.core.usercenter.oauth.qq;

import com.ciip.cloud.core.usercenter.handler.CustomAuthenticationFailureHandler;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

/**
 * Title: QqAuthenticationConfig
 * Description: TODO
 *
 * @author 
 * @created 2019/5/8 17:10
 */
@Component
public class QqAuthenticationConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    QqLoginSuccessHandler smsLoginSuccessHandler;

    @Autowired
    private CiipUserService userService;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        QqAuthenticationFilter smsAuthenticationFilter = new QqAuthenticationFilter();
        smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        smsAuthenticationFilter.setAuthenticationSuccessHandler(smsLoginSuccessHandler);
        smsAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);

        QqAuthenticationProvider smsAuthenticationProvider = new QqAuthenticationProvider();
        smsAuthenticationProvider.setUserService(userService);

        http.authenticationProvider(smsAuthenticationProvider)
                .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

    }
}

8.QQ身份验证筛选器:(验证是否通过)

package com.ciip.cloud.core.usercenter.oauth.qq;

import com.ciip.cloud.core.common.constant.usercenter.AddableHttpRequest;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Title: QqAuthenticationFilter
 * Description: TODO
 *
 * @author 
 * @created 
 */

public class QqAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private boolean postOnly = true;
    public QqAuthenticationFilter() {
        super(new AntPathRequestMatcher(CIIPCommonConstant.OAUTH_LOGIN_URL.QQ_LOGIN, HttpMethod.POST.name()));
    }

    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        //获取openId
        AddableHttpRequest addableHttpRequest = ((AddableHttpRequest) request);
        String openId = addableHttpRequest.getParameter("openId");
        //进行登录认证
        QqAuthenticationToken authRequest = new QqAuthenticationToken(openId);
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    protected void setDetails(HttpServletRequest request,
                              QqAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }
}

9.QQ身份验证提供程序:

package com.ciip.cloud.core.usercenter.oauth.qq;

import com.ciip.cloud.core.usercenter.service.CiipUserService;
import com.ciip.cloud.core.usercenter.vo.UserLoginVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * Title: QqAuthenticationProvider
 * Description: TODO
 *
 * @author 
 * @created 2019/5/8 16:58
 */

public class QqAuthenticationProvider implements AuthenticationProvider {


    private CiipUserService userService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        QqAuthenticationToken authenticationToken = (QqAuthenticationToken) authentication;
        String  openId =(String) authenticationToken.getPrincipal();
        UserDetails userDetails = userService.findByOpenId(openId);
        if (userDetails == null)
            throw new InternalAuthenticationServiceException("未找到与该QQ号对应的用户");
        QqAuthenticationToken authenticationResult = new QqAuthenticationToken(userDetails, userDetails.getAuthorities());
        authenticationResult.setDetails(authenticationToken.getDetails());
        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return QqAuthenticationToken.class.isAssignableFrom(aClass);
    }

    public CiipUserService getUserService() {
        return userService;
    }

    public void setUserService(CiipUserService userService) {
        this.userService = userService;
    }
}

10.QQ身份验证令牌:

package com.ciip.cloud.core.usercenter.oauth.qq;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;

import java.util.Collection;

/**
 * Title: QqAuthenticationToken
 * Description: TODO
 *
 * @author 
 * @created 2019/5/8 16:57
 */

public class QqAuthenticationToken extends AbstractAuthenticationToken {

    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    private final Object principal;

    public QqAuthenticationToken(Object openId) {
        super(null);
        this.principal = openId;
        setAuthenticated(false);
    }

    public QqAuthenticationToken(Object principal,
                                 Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        super.setAuthenticated(true);
    }

    public Object getPrincipal() {
        return this.principal;
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException(
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }

        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
    }
}

11.QQ前置过滤器:

package com.ciip.cloud.core.usercenter.oauth.qq;

import com.alibaba.fastjson.JSON;
import com.ciip.cloud.core.common.constant.usercenter.AddableHttpRequest;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.common.vo.ResultUtil;
import com.ciip.cloud.core.common.vo.usercenter.OauthCode;
import com.ciip.cloud.core.usercenter.exception.ValidateCodeException;
import com.ciip.cloud.core.usercenter.handler.CustomAuthenticationFailureHandler;
import com.ciip.cloud.core.usercenter.model.CiipUser;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import com.ciip.cloud.core.usercenter.service.QQAuthService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Title: QQCodeFilter
 * Description: TODO
 *
 * @author 
 * @created 2019/5/27 9:37
 */
@Component
public class QQCodeFilter extends OncePerRequestFilter {

    @Autowired
    private CustomAuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    private CiipUserService ciipUserService;
    @Autowired
    QQAuthService qqAuthService;

    /**
     * 过滤器:
     *        1.分为登录成功直接跳转到登录页面,登录失败表示未绑定跳转到注册页面
     *        2.如果已经登录,则可以进行绑定,并且验证一个QQ号只能绑定一个账号
     *          
     *
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String openId ="";
        if (StringUtils.equalsIgnoreCase(request.getContextPath()+ CIIPCommonConstant.OAUTH_LOGIN_URL.QQ_LOGIN, request.getRequestURI()) && StringUtils.equalsIgnoreCase(request.getMethod(), HttpMethod.POST.name())) {

            //1.根据code,获取openId
            String code = request.getParameter("code");
            openId = qqAuthService.getQQAccessToken(code);
            
            //2.将openId放入request请求对象中,并进行验证 
            AddableHttpRequest wrappedRequest = new AddableHttpRequest(request);
            wrappedRequest.addParameter("openId",openId);
                
            //3.获取当前用户【登录用户】 
            CiipUser ciipUser = ciipUserService.getCurrent();

            //4.不为空,表示为登录状态,用于绑定用户
             if(null != ciipUser && ("".equals(ciipUser.getOpenId()) || null == ciipUser.getOpenId())){

                 //5.绑定前验证,根据openId,获取对象【防止一个QQ绑定多个用户】
                 CiipUser ciipUserInfo = ciipUserService.findCiipUserByOpenId(openId);

                 //不为空,表示该QQ号已经绑定其他用户,跳转到绑定页面(status=false:表示不能绑定,前端根据该参数给出“您的QQ已绑定过了,请核实.”的提示,name=QQ:该参数来区分微信,QQ,微博类型)
                 if(null != ciipUserInfo){
                     response.sendRedirect(thirdLoginConstants.getUrl()+"/account/binding?status=false&name=QQ");
                     return;
                 }

                 ciipUser.setOpenId(openId);
                 //绑定,给用户表中添加QQId,表示绑定成功
                 ciipUserService.addCiipUser(ciipUser);

                  //添加系统消息--QQ绑定成功      
                 CiipUserMessage ciipUserMessage = new CiipUserMessage();
                 Map<String,Object> paramsMap = new HashMap<String, Object>();
                 ciipUserMessage.setCreateDate(new Date());
                 ciipUserMessage.setSoruceId(ciipUser.getId());
                 ciipUserMessage.setCreateUserId(ciipUser.getId());
                 ciipUserMessage.setCreateUserName(ciipUser.getUsername());
                 ciipUserMessage.setReceiveUserId(ciipUser.getId());
                 ciipUserMessage.setMessageBusinessType(CiipMessageBusinessType.BINDING_QQ);
                 ciipUserMessage.setMessageType(CiipMessageType.SYSTEM);
                 ciipUserMessage.setMsgTitle("QQ绑定成功");
                 ciipUserMessage.setMsgBody(StrUtil.format(CiipUserMessageTemplate.getOperationInfo(17),paramsMap));
                 ciipUserMessageService.addMessage(ciipUserMessage);

                 response.setHeader("Content-Type", "application/json;charset=UTF-8");
                 //跳转到绑定页面,绑定成功
                 response.sendRedirect(thirdLoginConstants.getUrl()+"/account/binding");

                 //byte[] bytes = JSON.toJSONBytes(ResultUtil.error(OauthCode.BINDING_SUCCESS.getCode(), OauthCode.BINDING_SUCCESS.getMsg(), request.getHeader("referer")));
                 //response.getOutputStream().write(bytes);
                 return;
             }else{
                 //为空,表示未登录,则登录前进行验证
                 try {
                     validateQQCode(openId);
                 } catch (ValidateCodeException e) {
                     authenticationFailureHandler.onAuthenticationFailure(request, response, e);
                     return;
                 }
             }
           
            filterChain.doFilter(wrappedRequest, response);
        }else{
            filterChain.doFilter(request, response);
        }
        
    }

    private void validateQQCode(String openId) throws ServletRequestBindingException, ValidateCodeException {
        //根据openId,获取用户信息
        UserDetails userDetails = ciipUserService.findByOpenId(openId);
        //表示该用户不存在,跳转到注册页面
        if(null == userDetails){
            throw new ValidateCodeException("该用户与QQ没有绑定或该用户不存在.");
        }
        //登录成功后,修改上次登录时间  
        CiipUser ciipUser = ciipUserService.findCiipUserByOpenId(openId);
        if(ciipUser != null){
            if(null != ciipUser.getLoginDate() && !"".equals(ciipUser.getLoginDate())){
                ciipUser.setLastLoggedDate(ciipUser.getLoginDate());
            }else{
                ciipUser.setLastLoggedDate(new Date());
            }
            ciipUser.setLoginDate(new Date());
            ciipUserRepository.saveAndFlush(ciipUser);
        }
    }
}

12.QQ登录成功处理程序:

package com.ciip.cloud.core.usercenter.oauth.qq;

import cn.hutool.core.lang.Console;
import cn.hutool.core.map.MapUtil;
import com.ciip.cloud.core.common.constant.enums.usercenter.CiipOperationMethod;
import com.ciip.cloud.core.common.constant.enums.usercenter.CiipOperationRecordType;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.common.vo.ResultUtil;
import com.ciip.cloud.core.common.vo.usercenter.OauthCode;
import com.ciip.cloud.core.usercenter.service.CiipUserOperationLogService;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import com.ciip.cloud.core.usercenter.vo.CiipUserInfo;
import com.ciip.cloud.core.usercenter.vo.UserInfo;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Title: QqLoginSuccessHandler 
 * Description: TODO
 *
 * @author 
 * @created 2019/5/8 18:01
 */
@Component
public class QqLoginSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Autowired
    private CiipUserOperationLogService ciipUserOperationLogService;

    private String redirectUrl ="/";
    @Autowired
    private CiipUserService ciipUserService;
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        try {
            String clientId =  request.getParameter("clientId");
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
            TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), clientId, clientDetails.getScope(), "mobile");
            OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);

            OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
            OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);

            Console.log("获取token 成功:{}", oAuth2AccessToken.getValue());

            UserInfo user =(UserInfo)authentication.getPrincipal();
            CiipUserInfo ciipUserInfo =  ciipUserService.getAuthUserInfo(Long.valueOf(user.getUserId()));

            //用户日志添加操作记录 
            Map<String,Object> paramsMap = new HashMap<String,Object>();
            paramsMap.put("currentUser", user.getUsername());
            ciipUserOperationLogService.addUserOperationLog(Long.valueOf(user.getUserId()),String.valueOf(user.getUserId()), CiipOperationRecordType.WEB_LOGIN.name(), CiipOperationMethod.QQ_LOGIN.name(), 11,paramsMap);

           //添加header认证信息
            response.setHeader(CIIPCommonConstant.AUTHORIZATION_HEADER, String.format("%s %s", CIIPCommonConstant.BEARER_TOKEN_TYPE,  oAuth2AccessToken.getValue().toString()));
            request.getSession().setAttribute(CIIPCommonConstant.BEARER_TOKEN,oAuth2AccessToken.getValue().toString());
            response.setHeader("Content-Type", "application/json;charset=UTF-8");
            //该方法为实现单点登录
            redisUtil.setWithExpireTime(CIIPCommonConstant.CIIP_AUTH,request.getSession().getId(), oAuth2AccessToken.getValue(),oAuth2AccessToken.getExpiresIn());
            //登录成功返回到首页
            response.sendRedirect(thirdLoginConstants.getUrl()+"/login");

            } catch (IOException e) {
            throw new BadCredentialsException(
                    "Failed to decode basic authentication token");
        }
    }


}

13.HttpServletRequestWrapper的封装,用户request中添加参数

package com.ciip.cloud.core.common.constant.usercenter;
/**
 * Title: AddableHttpRequest
 * Description: TODO
 *
 * @author 
 * @created 2019/5/28 15:12
 */

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;

public class AddableHttpRequest extends HttpServletRequestWrapper {

    private HttpServletRequest wrapped;

    private Map<String, String[]> parameterMap;

    public AddableHttpRequest(HttpServletRequest wrapped) {
        super(wrapped);
        this.wrapped = wrapped;
    }

    public void addParameter(String name, String value) {
        if (parameterMap == null) {
            parameterMap = new HashMap<String, String[]>();
            parameterMap.putAll(wrapped.getParameterMap());
        }
        String[] values = parameterMap.get(name);
        if (values == null) {
            values = new String[0];
        }
        List<String> list = new ArrayList<String>(values.length + 1);
        list.addAll(Arrays.asList(values));
        if(!"".equals(value)){
            list.add(value);
        }
        parameterMap.put(name, list.toArray(new String[0]));
    }

    @Override
    public String getParameter(String name) {
        if (parameterMap == null) {
            return wrapped.getParameter(name);
        }

        String[] strings = parameterMap.get(name);
        if (strings != null) {
            return strings[0];
        }
        return null;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        if (parameterMap == null) {
            return wrapped.getParameterMap();
        }

        return Collections.unmodifiableMap(parameterMap);
    }

    @Override
    public Enumeration<String> getParameterNames() {
        if (parameterMap == null) {
            return wrapped.getParameterNames();
        }

        return Collections.enumeration(parameterMap.keySet());
    }

    @Override
    public String[] getParameterValues(String name) {
        if (parameterMap == null) {
            return wrapped.getParameterValues(name);
        }
        return parameterMap.get(name);
    }
}

14.自定义身份验证失败处理程序:

package com.ciip.cloud.core.usercenter.handler;

import com.alibaba.fastjson.JSON;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.common.vo.ResultUtil;
import com.ciip.cloud.core.common.vo.usercenter.OauthCode;
import com.ciip.cloud.core.usercenter.service.CiipLoginHistoryService;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    private String failureUrl = "/signIn";

    @Autowired
    CiipUserService ciipUserService;
    @Autowired
    CiipLoginHistoryService ciipLoginHistoryService;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response, AuthenticationException exception) throws IOException {

            AddableHttpRequest addableHttpRequest = ((AddableHttpRequest) request);
            String openId = addableHttpRequest.getParameter("openId");
            String type = addableHttpRequest.getParameter("type");
            response.setHeader("Content-Type", "application/json;charset=UTF-8");
            log.info("--------------未绑定,经跳转到注册页面--------------");
            log.info("--------------openId--------------"+openId);
            log.info("--------------type--------------"+type);
            //跳转到注册页面,并带openId参数用于注册时直接绑定QQ账号,type参数是微信,QQ,微博类型
            response.sendRedirect(thirdLoginConstants.getUrl()+"/register?id="+ EncryptUtil.encrypt(openId)+"&type="+type);
            //byte[] bytes = JSON.toJSONBytes(ResultUtil.error(OauthCode.USERCENTER_OAUTH_LOGIN_ERROR.getCode(),OauthCode.USERCENTER_OAUTH_LOGIN_ERROR.getMsg()+""+exception.getMessage(),request.getHeader("referer")));
            //response.getOutputStream().write(bytes);
     
    }
}

15.验证异常:

package com.ciip.cloud.core.usercenter.exception;

import org.springframework.security.core.AuthenticationException;

/**
 * Title: ValidateCodeException
 * Description: TODO
 *
 * @author 
 * @created 2019/5/8 18:33
 */

public class ValidateCodeException extends AuthenticationException {


    public ValidateCodeException(String message) {
        super(message);
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值