认证服务-----技术点及亮点1

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 认证服务-----技术点及亮点

大技术

Nacos做注册中心

把新建的微服务注册到Nacos上去


两个步骤

  • 在配置文件中配置应用名称、nacos的发现注册ip地址,端口号
  • 在启动类上用@EnableDiscoveryClient注解开启注册功能


使用Redis存验证码信息

加入依赖配置地址和端口号即可

直接注入StringRedisTemplate模板类用就是

使用如下

//根据key获取redis中的值


String redisCode= redisTemplate.opsForValue().get(redis中的key值);


//存值到Redis中


redisTemplate.opsForValue().set(key值,value值,过期时间, 过期单位(TimeUnit.MINUTES));


使用gitee作社交登录(OAuth2.0)(亮点1)

这里由于微博开发者权限申请太慢了就使用gitee来实现社交登录

社交登录的步骤

(1)前端调用第三方应用作为社交登录

这个跟以往的模式不一样,以往是前段直接给后端发送请求,然后后端处理请求,这个是先调用第三方应用作为社交登录(也就是先跳转到gitee的登录授权页面),然后用户登录自己的gitee账号密码进行授权,授权成功后会跳转到指定的应用回调地址,然后在后端来处理这个应用回调地址的请求


gitee开发者后台管理链接:https://gitee.com/oauth/applications/16285

调用gitee第三方登录的url地址:<a href="https://gitee.com/oauth/authorize?client_id=自己应用的Client ID&redirect_uri=自己应用的成功回调地址&response_type=code&state=1">

<li>
  <a href="https://gitee.com/oauth/authorize?client_id=32459f971ce6d89cfb9f70899525455d0653cb804f16b38a304e3447dc97d673&redirect_uri=http://auth.saodaimall.com/callback&response_type=code&state=1">
    <img style="width: 50px;height: 18px;margin-top: 35px;" src="/static/login/JD_img/gitee.png"/>
  </a>
</li>


(2)社交服务OAuth2Controller来处理应用回调地址/callback请求

分流程:(其实就只有三行代码是要自己配置的(OAuth2Controller的gitee的42-44行),其他的基本上是固定的)


1>封装AccessTokenDTO对象然后发给码云服务器,如果AccessTokenDTO对象正确的话就返回一个access_token通行令牌(其实准确来说是用户授权后会返回一个code,然后把code和其他一些信息封装成AccessTokenDTO对象去找码云服务器获取到一个access_token通行令牌,最后通过这个access_token通行令牌去找码云服务器要这个用户在gitee上公开的资料信息)


2>获取到了access_token通行令牌去找码云服务器取该用户的公开信息并且转为通用gitee社交登录GiteeUser对象


3>远程调用会员服务来进行社交登录

package com.saodai.saodaimall.auth.controller;
import com.alibaba.fastjson.TypeReference;
import com.saodai.common.utils.R;
import com.saodai.common.vo.MemberResponseVo;
import com.saodai.saodaimall.auth.component.GitheeProvider;
import com.saodai.saodaimall.auth.feign.MemberFeignService;
import com.saodai.saodaimall.auth.vo.AccessTokenDTO;
import com.saodai.saodaimall.auth.vo.GiteeUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
import static com.saodai.common.constant.AuthServerConstant.LOGIN_USER;
/**
* 社交第三方授权登录
**/
@Slf4j
@Controller
public class OAuth2Controller {
    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private AccessTokenDTO accessTokenDTO;
    @Autowired
    private GitheeProvider githeeProvider;
    @GetMapping(value = "/callback")
    // /callback?code=e867a1f4575d4a6161e3249423a0403898253bc593e4b031a8771739ee6769f5&state=1
    public String gitee(@RequestParam(name = "code") String code,@RequestParam(name = "state") String state, HttpSession session) throws Exception {
        System.out.println(code);
        //下面三行代码都是自己应用的值,可以在gitee的第三方应用中看到对应的值
        accessTokenDTO.setClient_id("32459f971ce6d89cfb9f70899525455d0653cb804f16b38a304e3447dc97d673");
        accessTokenDTO.setClient_secret("f3046c911c03cadcded986062708150d4232af3ca6aef0259e5a0198d2c15ba5");
        accessTokenDTO.setRedirect_uri("http://auth.saodaimall.com/callback");
        accessTokenDTO.setCode(code);
        accessTokenDTO.setState(state);
        String accessToken = githeeProvider.getAccessToken(accessTokenDTO);
        //2、处理
        if (!StringUtils.isEmpty(accessToken)) {
            //获取到了access_token,转为通用gitee社交登录对象
            GiteeUser giteeUser = githeeProvider.getGiteeUser(accessToken);
            //知道了哪个社交用户
            //1)、当前用户如果是第一次进网站,自动注册进来(为当前社交用户生成一个会员信息,以后这个社交账号就对应指定的会员)
            //登录或者注册这个社交用户
            //调用远程服务
            R oauthLogin = memberFeignService.oauthLogin(giteeUser);
            if (oauthLogin.getCode() == 0) {
                MemberResponseVo memberResponseVo = oauthLogin.getData("data", new TypeReference<MemberResponseVo>() {});
                log.info("登录成功:用户信息:{}",memberResponseVo.toString());
                //1、第一次使用session,命令浏览器保存卡号,JSESSIONID这个cookie
                //以后浏览器访问哪个网站就会带上这个网站的cookie
                //TODO 1、默认发的令牌。当前域(解决子域session共享问题)
                //TODO 2、使用JSON的序列化方式来序列化对象到Redis中
                session.setAttribute(LOGIN_USER,memberResponseVo);
                //2、登录成功跳回首页
                return "redirect:http://saodaimall.com";
            } else {
                return "redirect:http://auth.saodaimall.com/login.html";
            }
        } else {
            return "redirect:http://auth.saodaimall.com/login.html";
        }
    }
}
package com.saodai.saodaimall.auth.vo;
/**
 * AccessTokenDTO对象封装(gitee社交登录令牌)
 */
import org.springframework.stereotype.Component;
@Component
public class AccessTokenDTO {
    private String client_id;
    private String client_secret;
    private String code;
    private String redirect_uri;
    private String state;
    public String getClient_id() {
        return client_id;
    }
    public void setClient_id(String client_id) {
        this.client_id = client_id;
    }
    public String getClient_secret() {
        return client_secret;
    }
    public void setClient_secret(String client_secret) {
        this.client_secret = client_secret;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getRedirect_uri() {
        return redirect_uri;
    }
    public void setRedirect_uri(String redirect_uri) {
        this.redirect_uri = redirect_uri;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
}
package com.saodai.saodaimall.auth.component;
import com.alibaba.fastjson.JSON;
import com.saodai.saodaimall.auth.vo.AccessTokenDTO;
import com.saodai.saodaimall.auth.vo.GiteeUser;
import okhttp3.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
 * 请求码云服务器
 */
@Component
public class GitheeProvider {
    //发起post请求获取AccessToken
    public String getAccessToken(AccessTokenDTO accessTokenDTO){
        MediaType mediaType= MediaType.get("application/json; charset=utf-8");
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(accessTokenDTO));
        Request request = new Request.Builder()
                .url("https://gitee.com/oauth/token?grant_type=authorization_code&code="+accessTokenDTO.getCode()+
                        "&client_id="+accessTokenDTO.getClient_id()+"&redirect_uri="+accessTokenDTO.getRedirect_uri()+
                        "&client_secret="+accessTokenDTO.getClient_secret())
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
            String string = response.body().string();
            System.out.println(string);
            String str1 = string.split(":")[1];
            String str2 = str1.split("\"")[1];
            return str2;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    //发起get请求返回GitUser对象,
    public GiteeUser getGiteeUser(String token){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url("https://gitee.com/api/v5/user?access_token="+token)
                .build();
        try (Response response = client.newCall(request).execute()) {
            String string=response.body().string();
            GiteeUser giteeUser = JSON.parseObject(string, GiteeUser.class);
            return giteeUser;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
package com.saodai.saodaimall.auth.vo;
import lombok.Data;
/**
 * GiteeUser对象封装(社交登录的gitee对象)
 */
@Data
public class GiteeUser {
    //gitee用户名称
    private String name;
    //gitee用户id
    private String id;
    //gitee用户自我介绍
    private String bio;
}

(3)远程调用会员服务来进行社交登录

/**
     * 社交登录
     * @param giteeUser
     * @return
     * @throws Exception
     */
  @PostMapping(value = "/oauth2/login")
    public R oauthLogin(@RequestBody GiteeUser giteeUser) throws Exception {
        MemberEntity memberEntity = memberService.login(giteeUser);
        if (memberEntity != null) {
            return R.ok().setData(memberEntity);
        } else {
            return R.error(BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getCode(),BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getMessage());
        }
    }
 /**
     * 社交登录
     * @param giteeUser
     * @return
     * @throws Exception
     */
    @Override
    public MemberEntity login(GiteeUser giteeUser) throws Exception {
        //获取gitee用户唯一id
        String giteeUserId = giteeUser.getId();
        //1、判断当前社交用户是否已经登录过系统
        MemberEntity memberEntity = this.baseMapper.selectOne(new QueryWrapper<MemberEntity>().eq("social_id", giteeUserId));
        //这个用户已经注册过
        if (memberEntity != null) {
            return memberEntity;
        } else {
            //2、没有查到当前社交用户对应的记录我们就需要注册一个
            MemberEntity register = new MemberEntity();
            //社交gitee登录的id作为会员id
            register.setId(Long.valueOf(giteeUserId));
            register.setSocialName(giteeUser.getName());
            register.setUsername(giteeUser.getName());
            register.setNickname(giteeUser.getName());
            register.setCreateTime(new Date());
            register.setSocialBio(giteeUser.getBio());
            register.setSocialId(giteeUserId);
            //把用户信息插入到数据库中
            this.baseMapper.insert(register);
            return register;
        }
    }
package com.saodai.saodaimall.member.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * 会员
 */
@Data
@TableName("ums_member")
public class MemberEntity implements Serializable {
  private static final long serialVersionUID = 1L;
  /**
   * id
   */
  @TableId
  private Long id;
  /**
   * 会员等级id
   */
  private Long levelId;
  /**
   * 用户名
   */
  private String username;
  /**
   * 密码
   */
  private String password;
  /**
   * 昵称
   */
  private String nickname;
  /**
   * 手机号码
   */
  private String mobile;
  /**
   * 邮箱
   */
  private String email;
  /**
   * 头像
   */
  private String header;
  /**
   * 性别
   */
  private Integer gender;
  /**
   * 生日
   */
  private Date birth;
  /**
   * 所在城市
   */
  private String city;
  /**
   * 职业
   */
  private String job;
  /**
   * 个性签名
   */
  private String sign;
  /**
   * 用户来源
   */
  private Integer sourceType;
  /**
   * 积分
   */
  private Integer integration;
  /**
   * 成长值
   */
  private Integer growth;
  /**
   * 启用状态
   */
  private Integer status;
  /**
   * 注册时间
   */
  private Date createTime;
  /**
   * 社交登录用户的ID
   */
  private String socialId;
  /**
   * 社交登录用户的名称
   */
  private String socialName;
  /**
   * 社交登录用户的自我介绍
   */
  private String socialBio;
}


整合SpringSession来解决session不同步不共享的问题(亮点2)

使用SpringSession的目的是来解决分布式session不同步不共享的问题。使用SpringSession可以把session都存在redis中,这样就解决了session不同步的问题,然后扩大作用域,这就解决了session不共享的问题,SpringSession不需要显性的操作(也就是不需要用StringRedisTemplate类的方法来把session放到redis中去,啥都不用干,就正常的把数据放到HttpSession中就可),由于整合了SpringSession,所以放到HttpSession中的数据会自动的放到redis中去,由于配置了序列化,所以session会被序列化json字符串放到redis中去,然后前端某个服务要取这个session的时候也会自动的redis中取


注意:由于这里使用springsession的用的类型是redis,所以这springsession和redis都要一起加入依赖和配置(所以session会被存到Redis缓存中)

相关实践学习
2分钟自动化部署人生模拟器
本场景将带你借助云效流水线Flow实现人生模拟器小游戏的自动化部署
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
目录
相关文章
|
NoSQL Java 关系型数据库
认证服务-----技术点及亮点2
认证服务-----技术点及亮点2
104 0
|
5月前
|
数据采集 安全 容灾
《阿里云产品手册2022-2023 版》——号码认证服务
《阿里云产品手册2022-2023 版》——号码认证服务
105 0
|
移动开发 API 开发工具
秒懂云通信:如何使用阿里云号码认证服务(小白指南)
手把手教你如何使用阿里云号码认证服务,超详细控制台步骤解析,快速上手!
3030 0
秒懂云通信:如何使用阿里云号码认证服务(小白指南)
|
安全 数据安全/隐私保护 开发者
阿里云通信发布全新号码认证服务, 重新定义手机号码认证的方式
12月12日,阿里云通信宣布号码认证服务正式商用,将重新定义手机号码认证的方式。因移动应用实名制的政策要求,手机号码认证在移动APP的注册、登录等场景用的越来越多。而对于开发者来说,能完成手机号码认证的选择并不多,一般是借助短信、语音的基础通信通道,自己实现短信验证码或语音验证码来实现。
25063 0
|
6月前
|
运维 小程序 前端开发
好的商业模式-----小程序定制资料,加一张好看的海报,在推广中就可以找到用户中了,云服务部署收5000,部署是一种服务,定制化,游戏开发创者,仲裁劳务会剪视频好,提供服务,想增加一些新功能收费,会说
好的商业模式-----小程序定制资料,加一张好看的海报,在推广中就可以找到用户中了,云服务部署收5000,部署是一种服务,定制化,游戏开发创者,仲裁劳务会剪视频好,提供服务,想增加一些新功能收费,会说
|
8月前
|
小程序 JavaScript IDE
【社区每周】如何实现小程序代码热更新?芝麻工作证新增“企业员工”职业身份验证(1月第四期)
【社区每周】如何实现小程序代码热更新?芝麻工作证新增“企业员工”职业身份验证(1月第四期)
70 0
|
消息中间件 NoSQL Java
订单服务------技术点及亮点1
订单服务------技术点及亮点
127 0
|
数据库
订单服务------技术点及亮点2
订单服务------技术点及亮点2
72 0