• 第三方登录接入-qq,weibo-java


    开发之前

    需求:网站接入qq,sina微博登录,本文最后付效果图:

    说明:大部分网站本身是需要用户概念的,很多操作依附于用户,而qq或微博作为一种登录方式指向用户而已,我参考了一下其他网站的做法,

    一般有如下两种做法:

    1,强制绑定:用户第一次通过qq登录时必须与该网站账户绑定,也就是用户必须要先有一个此网站账户才能登录成功

    2,互相独立,用户第一次通过qq登录时直接重新为用户注册一个账户,如以用户名为qq_123456直接注册一个账户,与其他账户无关;

    站在用户角度考虑下,可能需要更多的选择性,因此我是如下考虑的:

    用户登录后在个人中心中也可设置绑定。

    ---------------------------------------------------------------------------------------------------

    文档说明

    现在大部分第三方的登录OAuth2.0为标准,所以开发流程基本都一致,一般都是一下步骤:

    1,申请接入,获取appid&appkey(接入后又第三方发放)

    2,用户登录第三方下发token,

    3,通过token获取用户唯一标示,一般是一个openId

    api地址:

    qq:http://wiki.connect.qq.com/api列表

    sina:http://open.weibo.com/wiki/授权机制

    qq&sina也提供了java sdk

    https://github.com/sunxiaowei2014/weibo4j-oauth2-beta3.1.1/

    http://qzonestyle.gtimg.cn/qzone/vas/opensns/res/doc/qqConnect_Server_SDK_java_v2.0.zip

    sina的虽然开源了,但里面很多代码写的有问题,用的之后需要注意

    ------------------------------------------------------------------------------------------------------------

    开发

    数据结构方面需要加以一张表用来维护登录方式和用户关联(通过openId以及登录方式确定唯一性)

    网站引入,appid,appkey,回调地址的配置有不再赘述了

    代码基本上参照sdk中的demo就可以了,

    简单贴一下controller(springMVC架构)中的代码吧

    AUthController为父类,存放一些第三方登录的通用方法,BindController为用户绑定提供方法,第三方登录的controller基本上就是一个登录跳转方法,一个回调方法,以及一些接口api的调用

    public abstract class AuthController extends BaseController {
        @Resource
        private JavaMailSender mailSender;
        
        @Resource
        private IBAuthService authService;
    
        protected LoginUser getU(BAuth auth){
            LoginUser loginUser= new LoginUser();
            loginUser.setAccessToken(auth.getAccessToken());
            loginUser
                    .setIcon(auth.getIcon() == null ? IPortalConstants.defaultIconUrl
                            : auth.getIcon());
            loginUser.setId(auth.getUser().getId());
            loginUser.setLoginType(auth.getType());
            loginUser.setNickName(auth.getNickName() == null ? auth.getUser()
                    .getNickName() : auth.getNickName());
            loginUser.setOpenId(auth.getOpenId());
            return loginUser;
        }
        
        protected LoginUser getU(User user){
            LoginUser loginUser= new LoginUser();
            loginUser
                    .setIcon(user.getIcon() == null ? IPortalConstants.defaultIconUrl
                            : user.getIcon());
            loginUser.setId(user.getId());
            loginUser.setLoginType(AuthType.bresume.getCode());
            loginUser.setNickName( user.getNickName());
            return loginUser;
        }
        
        protected boolean setUser2Session(BAuth auth){
            LoginUser loginuser = this.getU(auth);
            SessionContextHolder.getSession().setAttribute(IPortalConstants.SESSION_KEY_LOGIN_USER, loginuser);
            return true;
        }
        
        protected boolean setUser2Session(User user){
            LoginUser loginuser = this.getU(user);
            SessionContextHolder.getSession().setAttribute(IPortalConstants.SESSION_KEY_LOGIN_USER, loginuser);
            return true;
        }
        
        protected void sendRegisterMail(User user,String code) {
            PropertiesLoader loader = new PropertiesLoader("mail.properties");
    
            Map<String, Object> map = new HashMap<String, Object>();
            Email email = new Email();
            email.setSender(loader.getProperty("mail.from"));
            email.setAddress(user.getEmail());
            
            email.setSubject(loader.getProperty("mail.register.success.subject"));
            // 从模板生成
            HashMap<String, Object> param = new HashMap<String, Object>();
            param.put("userName", user.getUserName());
            param.put("userId", user.getId());
            param.put("code", code);
            email.setContent(MailUtils.getMailText(param,
                    loader.getProperty("mail.register.success.content")));
            map.put("email", email);
            MailUtils.sendMailByAsynchronousMode(map, mailSender);
    
        }
        
        protected String callBack(Model model,BAuth newAuth){
            BAuth oldAuth = authService.findOne(newAuth.getOpenId(),newAuth.getType());
            if (oldAuth != null && oldAuth.getUser() != null) {
                // 判定有登录记录
                //刷新accessToken
                oldAuth.setAccessToken(newAuth.getAccessToken());
                oldAuth.setExpiresIn(newAuth.getExpiresIn());
                oldAuth.setIcon(newAuth.getIcon());
                oldAuth.setNickName(newAuth.getNickName());
                oldAuth.setRefreshAccessTime(new Date());
                authService.update(oldAuth);
                this.setUser2Session(oldAuth);
                return "redirect:/index";
            } else if(oldAuth==null) {
                // 判定首次登录,记录
                oldAuth = new BAuth();
                oldAuth.setAccessToken(newAuth.getAccessToken());
                oldAuth.setExpiresIn(newAuth.getExpiresIn());
                oldAuth.setCreatedTime(new Date());
                oldAuth.setIcon(newAuth.getIcon());
                oldAuth.setNickName(newAuth.getNickName());
                oldAuth.setOpenId(newAuth.getOpenId());
                oldAuth.setRefreshAccessTime(new Date());
                oldAuth.setType(newAuth.getType());
                authService.save(oldAuth);
                //用户绑定,跳转页面
                model.addAttribute("openId", newAuth.getOpenId());
                model.addAttribute("loginFrom", newAuth.getType());
                return "site/bindAuth.jsp";
            }else{
                // 登录过但因某种原因为绑定账户
                oldAuth.setAccessToken(newAuth.getAccessToken());
                oldAuth.setExpiresIn(newAuth.getExpiresIn());
                oldAuth.setIcon(newAuth.getIcon());
                oldAuth.setNickName(newAuth.getNickName());
                oldAuth.setRefreshAccessTime(new Date());
                authService.update(oldAuth);
                //用户绑定,跳转页面
                model.addAttribute("openId", newAuth.getOpenId());
                model.addAttribute("loginFrom", newAuth.getType());
                return "site/bindAuth.jsp";
            }
    
        }
        
    }
    AuthController
    @RequestMapping("/")
    @Controller
    public class BindController extends AuthController {
    
        @Resource
        private IUserService userService;
    
        @Resource
        private IBAuthService authService;
    
        @Resource
        private IUserVerifiedService verifiedService;
    
        @Resource
        private JavaMailSender mailSender;
    
        @RequestMapping("/ingore-bind")
        public String ingore_bind(
                @RequestParam(value = "loginFrom", required = true) Integer loginFrom,
                @RequestParam(value = "openId", required = true) String openId,
                ModelMap model, HttpServletResponse response) {
            BAuth auth = authService.findOne(openId, loginFrom);
            if (auth == null) {
                return "404";
            }
            if (auth.getUser() == null) {
                User user = new User();
                /*
                 * user.setUserName(userName); user.setPassword(password);
                 */
                // user.setEmail(email);
                user.setNickName(auth.getNickName());
                user.setIcon(auth.getIcon());
    
                user.setRegisterType(AuthType.fromCode(loginFrom).getRt().getType());
                user.setType(UserType.PERSIONAL.getCode());
                user.setLevel(0);
                userService.registerFromAuth(user);
                auth.setUser(user);
                authService.save(auth);
            }
    
            this.setUser2Session(auth);
            return "redirect:/index";
        }
    
        @RequestMapping("/login-bind")
        public @ResponseBody JSONObject bind(
                @RequestParam(value = "loginFrom", required = true) Integer loginFrom,
                @RequestParam(value = "openId", required = true) String openId,
                @RequestParam(value = "email", required = true) String email,
                @RequestParam(value = "password", required = true) String password,
                ModelMap model, HttpServletResponse response) {
    
            BAuth auth = authService.findOne(openId, loginFrom);
            if (auth == null) {
                return this.toJSONResult(false,"404");
            }
    
            if (auth.getUser() == null) {
                try {
                    // 登陆校验
                    User user = userService.loginCheck(email, password);
                    auth.setUser(user);
                    authService.update(auth);
                } catch (CoreException e) {
                    if (e.getErrorCode() == PortalErrorCode.USER_PASSWORD_ERROR_TIMES_EXCEED_ERROR) {
                        return this.toJSONResult(false,
                                this.getMessage(e, e.getArgs()));
                    } else {
    
                        return this.toJSONResult(false, this.getMessage(e));
                    }
                }
            }
    
            this.setUser2Session(auth);
            return this.toJSONResult(true);
        }
    
        @RequestMapping("/regist-bind")
        public @ResponseBody JSONObject registBind(
                @RequestParam(value = "loginFrom", required = true) Integer loginFrom,
                @RequestParam(value = "openId", required = true) String openId,
                @RequestParam(value = "email", required = true) String email,
                @RequestParam(value = "password", required = true) String password,
                ModelMap model, HttpServletResponse response) {
            BAuth auth = authService.findOne(openId, loginFrom);
            if (auth == null) {
                return this.toJSONResult(false);
            }
            if (auth.getUser() == null) {
                User user=new User();
    //            user.setUserName(userName);
                user.setPassword(password);
                user.setEmail(email);
    
                try {
                    user.setRegisterType(RegisterType.PORTAL_REGISTER.getType());
                    user.setType(UserType.PERSIONAL.getCode());
                    user.setLevel(0);
                    user.setNickName(auth.getNickName());
                    user.setIcon(auth.getIcon());
                    userService.register(user);
                    //生成邮箱验证码
                    UserVerified uv = new UserVerified(user);
                    verifiedService.save(uv);
                    // 发送注册成功的邮件
                    if (CommonUtils.isNotEmpty(user.getEmail())) {
                        sendRegisterMail(user,uv.getCode());
                    }
                } catch (CoreException e) {
                    return this.toJSONResult(false, this.getMessage(e));
                }
                auth.setUser(user);
                authService.save(auth);
            }
    
            this.setUser2Session(auth);
            return this.toJSONResult(true);
        }
    
    }
    BindController
    @RequestMapping("/")
    @Controller
    public class QQController extends AuthController {
    
        @Resource
        private IBAuthService authService;
    
        @Resource
        private IUserService userService;
    
        @RequestMapping("/qqlogin")
        public void index(HttpServletRequest request, HttpServletResponse response,
                Model model) throws IOException {
            response.setContentType("text/html;charset=utf-8");
            try {
                response.sendRedirect(new Oauth().getAuthorizeURL(request));
                LOGGER.info("login by qq");
            } catch (QQConnectException e) {
                e.printStackTrace();
            }
        }
    
        @RequestMapping("/qq_callback")
        public String callback(HttpServletRequest request,
                HttpServletResponse response, Model model) {
            try {
                AccessToken accessTokenObj = (new Oauth())
                        .getAccessTokenByRequest(request);
    
                String accessToken = null, openID = null;
                long tokenExpireIn = 0L;
    
                if (accessTokenObj.getAccessToken().equals("")) {
                    LOGGER.error("QQ Login failed,caused by 没有获取到响应参数");
                    return "404";
                }
    
                accessToken = accessTokenObj.getAccessToken();
                tokenExpireIn = accessTokenObj.getExpireIn();
                LOGGER.info("Get accessToken from qq,accessToken:" + accessToken
                        + ",tokenExpireIn" + tokenExpireIn);
    
                // 利用获取到的accessToken 去获取当前用的openid
                OpenID openIDObj = new OpenID(accessToken);
                openID = openIDObj.getUserOpenID();
                LOGGER.info("利用获取到的accessToken:" + accessToken
                        + ", 去获取到当前用户openid:" + openID + ".");
    
                String icon = null, nickName = null;
                // 去获取用户在Qzone的昵称等信息
                UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);
                UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();
    
                if (userInfoBean.getRet() == 0) {
                    nickName = userInfoBean.getNickname();
                    // userInfoBean.getGender();
    
                    icon = userInfoBean.getAvatar().getAvatarURL30();
                    // userInfoBean.getAvatar().getAvatarURL50();
                    // userInfoBean.getAvatar().getAvatarURL100();
                } else {
                    LOGGER.error("很抱歉,我们没能正确获取到您的信息,原因是:" + userInfoBean.getMsg());
                }
    
                BAuth newAuth = new BAuth();
                newAuth.setAccessToken(accessToken);
                newAuth.setExpiresIn(tokenExpireIn);
                newAuth.setIcon(icon);
                newAuth.setNickName(nickName);
                newAuth.setOpenId(openID);
                newAuth.setType(AuthType.QQ.getCode());
                return this.callBack(model, newAuth);
                
                // 通过openid判断首次登录与否
            /*    BAuth bauth = authService.findOne(openID, AuthType.QQ.getCode());
                if (bauth != null && bauth.getUser() != null) {
                    // 判定有登录记录
                    //刷新accessToken
                    bauth.setAccessToken(accessToken);
                    bauth.setExpiresIn(tokenExpireIn);
                    bauth.setIcon(icon);
                    bauth.setNickName(nickName);
                    bauth.setRefreshAccessTime(new Date());
                    authService.update(bauth);
                    this.setUser2Session(bauth);
                    return "redirect:/index";
                } else if(bauth==null) {
                    // 判定首次登录,记录
                    bauth = new BAuth();
                    bauth.setAccessToken(accessToken);
                    bauth.setCreatedTime(new Date());
                    bauth.setExpiresIn(tokenExpireIn);
                    bauth.setIcon(icon);
                    bauth.setNickName(nickName);
                    bauth.setOpenId(openID);
                    bauth.setRefreshAccessTime(new Date());
                    bauth.setType(AuthType.QQ.getCode());
                    authService.save(bauth);
                    //用户绑定,跳转页面
                    model.addAttribute("openId", openID);
                    model.addAttribute("loginFrom", AuthType.QQ.getCode());
                    return "site/bindAuth.jsp";
                }else{
                    // 登录过但因某种原因为绑定账户
                    bauth.setAccessToken(accessToken);
                    bauth.setExpiresIn(tokenExpireIn);
                    bauth.setIcon(icon);
                    bauth.setNickName(nickName);
                    bauth.setRefreshAccessTime(new Date());
                    authService.update(bauth);
                    //用户绑定,跳转页面
                    model.addAttribute("openId", openID);
                    model.addAttribute("loginFrom", AuthType.QQ.getCode());
                    return "site/bindAuth.jsp";
                }*/
    
            } catch (QQConnectException e) {
                e.printStackTrace();
            }
            return "redirect:/index";
        }
    
        @RequestMapping("/qqss")
        public void talk(HttpServletRequest request, HttpServletResponse response,
                Model model) throws IOException {
            response.setContentType("text/html;charset=utf-8");
    
            request.setCharacterEncoding("utf-8");
            String con = request.getParameter("con");
            HttpSession session = request.getSession();
            String accessToken = (String) session.getAttribute("demo_access_token");
            String openID = (String) session.getAttribute("demo_openid");
            System.out.println(accessToken);
            System.out.println(openID);
            // 请开发者自行校验获取的con值是否有效
            if (con != "") {
                Topic topic = new Topic(accessToken, openID);
                try {
                    GeneralResultBean grb = topic.addTopic(con);
                    if (grb.getRet() == 0) {
                        response.getWriter()
                                .println(
                                        "<a href="http://www.qzone.com" target="_blank">您的说说已发表成功,请登录Qzone查看</a>");
                    } else {
                        response.getWriter().println(
                                "很遗憾的通知您,发表说说失败!原因: " + grb.getMsg());
                    }
                } catch (QQConnectException e) {
                    System.out.println("抛异常了?");
                }
            } else {
                System.out.println("获取到的值为空?");
            }
        }
    }
    QQController
    @RequestMapping("/")
    @Controller
    public class SinaController extends AuthController {
    
        @Resource
        private IBAuthService authService;
    
        @Resource
        private IUserService userService;
    
        @RequestMapping("/sinalogin")
        public void index(HttpServletRequest request, HttpServletResponse response,
                Model model) throws IOException {
            response.setContentType("text/html;charset=utf-8");
            try {
                response.sendRedirect(new Oauth().authorize("code"));
                LOGGER.info("login by weibo");
            } catch (WeiboException e) {
                e.printStackTrace();
            }
    
        }
    
        @RequestMapping("/weibo_callback")
        public String callback(HttpServletRequest request,
                HttpServletResponse response, Model model) throws IOException {
            try {
                Oauth oauth = new Oauth();
                String code = request.getParameter("code");
                LOGGER.info("code: " + code);
                AccessToken accessTokenObj = oauth.getAccessTokenByCode(code);
                if (accessTokenObj == null) {
                    LOGGER.error("AccessToken 获取失败,code:" + code);
                }
                String accessToken = accessTokenObj.getAccessToken();
                String openId = accessTokenObj.getUID();
    
                String expireInStr = accessTokenObj.getExpireIn();
    
                Users um = new Users(accessToken);
                User user = um.showUserById(openId);
                LOGGER.info(user.toString());
    
                BAuth newAuth = new BAuth();
                newAuth.setAccessToken(accessToken);
                newAuth.setExpiresIn(expireInStr != null ? Long
                        .parseLong(expireInStr) : 3600);
                newAuth.setIcon(user.getAvatarLarge());
                newAuth.setNickName(user.getScreenName());
                newAuth.setOpenId(openId);
                newAuth.setType(AuthType.SINA.getCode());
                return this.callBack(model, newAuth);
    
            } catch (WeiboException e) {
                if (401 == e.getStatusCode()) {
                    LOGGER.error("Unable to get the access token.");
                } else {
                    e.printStackTrace();
                }
            }
    
            return "redirect:/index";
        }
    
    }
    SinaController

    -------------------------------------------------------------------------------------------------------------

    页面效果

    注:该流程为用户首次使用第三方登录时流程

    1,登录页面放置第三方登录图标

    2,点击图标接入第三方接口,可跳转至第三方登录界面

    3,第三方登录完成,用户账户绑定

    4,用户登录后,可在个人设置中管理第三方登录的绑定

  • 相关阅读:
    P7276-送给好友的礼物【dp】
    P4831-Scarlet loves WenHuaKe【组合数学】
    CF461D-Appleman and Complicated Task【并查集】
    P6499-[COCI2016-2017#2]Burza【状压dp】
    CF757F-Team Rocket Rises Again【最短路,DAG支配树】
    Loj#6053-简单的函数【Min25筛】
    P5325-[模板]Min_25筛
    2019.10.6 机房训练赛
    [CSP校内集训]v(记忆化搜索+map优化状压)
    [CSP校内集训]ac(树上启发式合并)
  • 原文地址:https://www.cnblogs.com/china2k/p/4217108.html
Copyright © 2020-2023  润新知