社交登录

社交登录,是指用户可以使用微博、QQ、微信等社交媒体账号登录网站。从用户的角度来看,社交登录不仅可以省去注册账号的操作过程,也可以不用记忆账号和密码,网站接入社交登录功能是真的香。该如何接入社交登录呢?接入流程是怎样的呢?别急,且听我慢慢道来。

一、环境搭建

1. 申请微博登录接口

以微博登录为例,你首先需要到微博开放平台申请一个网页应,填写应哟用相关信息。

等待审核通过,就可以获得一个App Key和App Secret,你需要设置授权回调页的地址,现在你就可以使用微博登入接口了。

2 社交登录流程

在微博开放平台有关于OAuth2.0协议的授权流程图。

我来带大家解读一下这个授权流程。

  1. 首先点击微博登录按钮,需要携带client_id和回调地址(必须和微博开放平台上设置的授权回调页地址相同)到如下地址 :
 https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
  1. 用户使用微博账号和密码进行授权,授权成功,重定向到:
 YOUR_REGISTERED_REDIRECT_URI/?code=CODE
  1. 接下来带着code码和回调地址,发送POST请求到微博的认证服务器换取access_token。

    https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE
    

    必须携带以下请求参数。

    • client_id:申请应用时分配的AppKey

    • client_secret:申请应用时分配的AppSecret

    • grant_type:请求的类型,authorization_code

    • redirect_url:回调地址,必须与注册应用里的回调地址一致

    • code:上一步骤返回的code码

    返回数据:


  2. 认证服务器验证通过,返回access_token,然后就可以拿着这个access_token去访问微博的API服务器,发送GET请求获取用户的开放信息。比如:根据用户id获取用户信息。

    https://api.weibo.com/2/users/show.json?access_token=ACCESS_TOKKEN&uid=用户ID
    

    返回数据

3 数据库设计

创建一张用户表,保存用户基本信息,并添加社交id和社交令牌字段,social_uid作为社交用户的唯一身份识别。

create table ums_member
(
   id                   bigint not null auto_increment comment 'id',
   username             char(64) comment '用户名',
   password             varchar(64) comment '密码',
   nickname             varchar(64) comment '昵称',
   profile_image_url    varchar(255) comment '头像地址',
   gender               tinyint comment '性别',
   create_time          datetime comment '注册时间',
   social_uid        varchar(255) comment '社交id',
   access_token        VARCHAR(255) COMMENT '社交令牌',
   primary key (id)
);

二、实现流程

1. 登录页面

微博登录按钮添加链接,引导用户到授权页面

 <div class="si_out">
   <a href="https://api.weibo.com/oauth2/authorize?client_id=APP_KEY&response_type=code&redirect_uri=http://auth.ylogin.com/oauth2.0/weibo/success">
     <img th:width="50px" th:height="18px" src="/static/login/JD_img/weibo.png" />
   </a>
</div>

2. 处理登录请求

  1. 首先获取到请求参数code的值,发送POST请求换取access_token,调用远程用户服务登录
@Slf4j
@Controller
public class OAuth2Controller {

  @Autowired
  UserFeignService userFeignService;

  @GetMapping("/oauth2.0/weibo/success")
  public String weibo(@RequestParam("code") String code, HttpSession session, HttpServletResponse servletResponse) throws Exception {

      // 通过Authorization Code获取Access Token
      Map<String, String> map = new HashMap<>();
      map.put("grant_type","authorization_code");
      map.put("client_id",""); //app id
      map.put("client_secret",""); //app key
      map.put("code",code);
      map.put("redirect_uri","http://auth.ylogin.com/oauth2.0/weibo/success");
      HttpResponse res = HttpUtils.doPost("https://api.weibo.com", "/oauth2/access_token", "post",new HashMap<String, String>(), map, (byte[]) null);
      // 成功换取Access Token
      if (res.getStatusLine().getStatusCode() == 200){
          // 获取返回数据
          String json = EntityUtils.toString(res.getEntity());
          SocialUserTo socialUserTo = JSON.parseObject(json, SocialUserTo.class);
          // 调用远程用户服务进行登录
          R r = userFeignService.socialLogin(socialUserTo);
          if (r.getCode() == 0) {
              UserResponseVo data = r.getData("data", new TypeReference<UserResponseVo>() {
              });
              log.info("登录成功!用户信息:{}",data.toString());
              session.setAttribute(AuthServerConstant.LOGIN_USER,data);
              return "redirect:http://ylogin.com";
          } else {
              return "redirect:http://auth.ylogin.com/login.html";
          }
      } else {
          return "redirect:http://auth.ylogin.com/login.html";
      }
  }
}
  1. 用户接收换取Access Token的请求返回数据的实体类
@Data
public class SocialUserTo {


    private String accessToken;

    private long expiresIn;

    private String refreshToken;

    private String uid;

    private String remindIn;


}

3. 用户登录

  1. 如果用户已经注册,直接登录;如果用户未进行注册,则拿access_token和用户id获取用户的信息,进行注册。
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Override
    public UserEntity login(SocialUserTo socialUserTo) {
        // 登陆和注册合并逻辑
        String uid = socialUserTo.getUid();
        UserDao userDao = this.baseMapper;
        UserEntity member = userDao.selectOne(new QueryWrapper<UserEntity>().eq("social_uid", uid));
        if (member != null){
            // 当前社交用户已经注册,更新用户的access_token
            UserEntity updateMember = new UserEntity();
            updateMember.setId(member.getId());
            updateMember.setAccessToken(socialUserTo.getAccessToken());
            userDao.updateById(updateMember);
            member.setAccessToken(socialUserTo.getAccessToken());
            return member;
        } else {
            // 没有查到当前社交用户,需要注册
            UserEntity register = new UserEntity();
            try {
                // 获取当前社交用户的信息
                Map<String, String> query= new HashMap<>();
                query.put("access_token",socialUserTo.getAccessToken());
                query.put("uid",socialUserTo.getUid());
                HttpResponse response = HttpUtils.doGet("https://api.weibo.com", "/2/users/show.json", "GET", new HashMap<String, String>(), query);
                if (response.getStatusLine().getStatusCode() == 200) {
                    // 查询成功
                    String json = EntityUtils.toString(response.getEntity());
                    JSONObject jsonObject = JSON.parseObject(json);
                    // 获取用户信息
                    register.setNickname(jsonObject.getString("name"));
                    register.setGender("m".equals(jsonObject.getString("gender")) ?1:0);
                    register.setProfileImageUrl(jsonObject.getString("profile_image_url"));
                }
            }catch (Exception e){ }
            register.setSocialUid(socialUserTo.getUid());
            register.setAccessToken(socialUserTo.getAccessToken());
            register.setCreateTime(new Date());
            userDao.insert(register);
            return register;
        }
    }
}
  1. 用户实体类
@Data
@TableName("user")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * id
     */
    @TableId
    private Long id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 昵称
     */
    private String nickname;
    /**
     * 头像
     */
    private String profileImageUrl;
    /**
     * 性别
     */
    private Integer gender;
    /**
     * 注册时间
     */
    private Date createTime;

    /**
     * 社交id
     */
    private String socialUid;
    /**
     * 社交令牌
     */
    private String accessToken;

}

4. 登录成功,跳转到主页

<div>
    <h1>
        欢迎:<img th:if="${session.loginUser != null}" th:src="${session.loginUser.profileImageUrl}"/>[[${session.loginUser.nickname}]]
    </h1>
</div>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容