第三方登录

采用流量较大的第三方,使用第三方登录,可以更好的留住用户

第三方登录其实是比较简单的,其实第三方已经给我们提供好了服务,实现第三方登录,我们只需要调用第三方给我们提供的接口,发送请求即可。不论QQ、微信还是微博,实现第三方登录的原理都是一样的,可能就是发送的url路径不一样、路径内的参数可能不一样,其他的操作步骤都是一样的

(一)OAuth2.0原理

OAuth2.0即Open Authorization,是身份认证的意思,所有的第三方登录都需要实现OAuth2.0原理。

(二)微信登录

  1. 准备WechatConstant微信登录的上下文
package cn.itsource.crm.shiro;

import cn.itsource.crm.domain.Employee;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

public enum UserContext {
    Utils;
    //准备一个常量
    private static final String USERNAME_IN_SESSION ="sessionUser";
    //将当前用户存入session
    public void setUser(Employee employee){
        //获取当前对象
        Subject subject = SecurityUtils.getSubject();
        //将员工对象放入session
        subject.getSession().setAttribute(USERNAME_IN_SESSION,employee);
    }
    //将用户从session中取出
    public Employee getUser(){
        //获取当前对象
        Subject subject = SecurityUtils.getSubject();
        //从session中拿值
        return (Employee)subject.getSession().getAttribute(USERNAME_IN_SESSION);
    }
}
  1. 登录类型
package cn.itsource.crm.shiro;

//登录类型,分为微信登录和普通系统用户登录
public enum LoginType {

    WechatLogin("Wechat"),EmployeeLogin("Employee");

    private String loginType;

    LoginType(String loginType) {
        this.loginType = loginType;
    }

    public String getLoginType() {
        return loginType;
    }

    public void setLoginType(String loginType) {
        this.loginType = loginType;
    }
}

  1. WechatRealm
    此处因为集成了shiro框架,使用的是多realm,判断登录的类型,是系统用户登录,还是第三方登录
package cn.itsource.crm.shiro;

import cn.itsource.crm.domain.Employee;
import cn.itsource.crm.service.EmployeeService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

public class WechatRealm extends AuthorizingRealm {


    @Autowired
    private EmployeeService employeeService;


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    /**
     * 身份认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //① 获取code
        CRMToken dmsToken = (CRMToken) token;
        String code = dmsToken.getUsername();
        //② 获取token
        String url = WechatConstant.TOKEN_URI.replaceAll("APPID",WechatConstant.APPID)
                        .replaceAll("SECRET",WechatConstant.SECRET)
                        .replaceAll("CODE",code);
        //借助httpClicen工具类,(使用的是java代码)发送请求,获取令牌
        String respStr = HttpClientUtils.doGet(url);
        Map respMap = HttpClientUtils.parseRespJson(respStr);
        String access_token = respMap.get("access_token");
        String openid = respMap.get("openid");

        //③ unionid
        url = WechatConstant.USER_INFO_URI.replaceAll("ACCESS_TOKEN",access_token)
                            .replaceAll("OPENID",openid);
        respStr = HttpClientUtils.doGet(url);
        String unionid = HttpClientUtils.parseRespJson(respStr).get("unionid");

        //查询数据库
        Employee employee = employeeService.getByUnionId(unionid);
        if(employee==null){
            SecurityUtils.getSubject().getSession().setAttribute("unionid",unionid);
            throw new NoUserBindingException();
        }
        SimpleAuthenticationInfo info
                = new SimpleAuthenticationInfo(employee,code,getName());
        return info;
    }
}
  1. 登录logincontroller
package cn.itsource.crm.web.controller;

import cn.itsource.basic.util.Message;
import cn.itsource.crm.domain.Employee;
import cn.itsource.crm.shiro.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@Controller
public class LoginController {

        //用于完成跳转
        @RequestMapping(value="/login",method = RequestMethod.GET)
        public String index(Model model){
            String url = WechatConstant.CODE_URL.replaceAll("APPID",WechatConstant.APPID)
                    .replaceAll("REDIRECT_URI",WechatConstant.REDIRECT_URI);

            model.addAttribute("authenUrl",url);
            return "forward:/WEB-INF/views/login.jsp";
        }

    /**
     * 微信登录用户授权后的回调
     * @param code
     * @return
     */
    @RequestMapping(value = "/callback",method = RequestMethod.GET)
    public String callback(String code){
        //code身份认证
        Subject currentUser = SecurityUtils.getSubject();
        CRMToken token = new CRMToken(code,code, LoginType.WechatLogin);
        try {
            currentUser.login(token);
            Employee employee = (Employee) currentUser.getPrincipal();
            UserContext.Utils.setUser(employee);
        }catch (NoUserBindingException e){
            e.printStackTrace();
            return "bind";
        }catch (AuthenticationException e) {
            e.printStackTrace();
            return "forward:/login";
        }
        //获取用户身份存入到session中
        return "main";
    }

    //登陆方法
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public Message login(String username, String password, String validation, HttpServletRequest req) {

        System.out.println("======================================="+username);
        System.out.println("======================================="+password);
        //拿到当前用户
        Subject subject = SecurityUtils.getSubject();
        if(!subject.isAuthenticated()) {
            try {
                //准备令牌,使用的是自定义的令牌
                UsernamePasswordToken token = new CRMToken(username, password,LoginType.EmployeeLogin);
                //登陆
                subject.login(token);
                //将当前用户存入session
                Employee employee = (Employee) subject.getPrincipal();
                UserContext.Utils.setUser(employee);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("用户名错误");
                return new Message(false, "用户名或密码错误!");
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                System.out.println("密码错误");
                return new Message(false, "用户名或密码错误!");
            } catch (AuthenticationException e) {
                e.printStackTrace();
                System.out.println("未知错误");
                return new Message(false, "发生了未知错误!请联系管理员");
            }
        }
        return new Message();
    }

    //登出功能
    @RequestMapping("/logout")
    public String logout() {
        System.out.println("我登出了");
        //拿到当前用户
        Subject subject = SecurityUtils.getSubject();
        //登出
        subject.logout();
        return "login";
    }

}

  1. BindController
    第一次使用第三方登录系统,需要进行绑定
package cn.itsource.crm.web.controller;

import cn.itsource.crm.domain.Employee;
import cn.itsource.crm.service.EmployeeService;
import cn.itsource.crm.shiro.CRMToken;
import cn.itsource.crm.shiro.LoginType;
import cn.itsource.crm.shiro.UserContext;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
public class BindController {

    @Autowired
    private EmployeeService employeeService;


    @RequestMapping(value = "/bind",method = RequestMethod.POST)
    public String bindUser(String username,String password){

        //查询用户名和密码是否正确
        //认证
        Subject currentUser = SecurityUtils.getSubject();
        CRMToken token = new CRMToken(username,password, LoginType.EmployeeLogin);
        try {
            currentUser.login(token);
            //认证成功,添加unionid
            Employee employee = (Employee) currentUser.getPrincipal();
            String unionid = (String) currentUser.getSession().getAttribute("unionid");
            employeeService.bindWechat(employee.getId(),unionid);
            //把用户信息存到session中
            UserContext.Utils.setUser(employee);
        } catch (AuthenticationException e) {
            //认证失败,返回登录页面
            e.printStackTrace();
            return "forward:/login";
        }
        return "main";
    }

}

你可能感兴趣的:(客户智能管理)