在线视频项目笔记总结(一)—登录相关接口

一、管理员登录接口

1.业务逻辑见代码:

controller层

@RestController
@Slf4j
public class AdminController {
    @Autowired
    private AdminService adminService;
    @Autowired
    private RedisTemplate redisTemplate;
    /**用户登录*/
    @PostMapping("/tokens")
    public Map<String,String> tokens(@RequestBody Admin admin, HttpSession session) {
       Map<String, String> result = new HashMap<>();
        //转json,fastjson有安全漏洞 推荐用jackson
        //log.info("接受到admin对象为:{}", JSONUtils.writeJSON(admin));
        // 登录
        Admin adminDB = adminService.login(admin);
        // 登录成功,获取token
        String token = session.getId();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.opsForValue().set(token,adminDB,30, TimeUnit.MINUTES);
        result.put("token",token);
        return result;
    }
}
@Service("adminService")
@Transactional //控制事务
public class AdminServiceImpl implements AdminService {
    @Resource
    private AdminDao adminDao;

    @Override
    public Admin login(Admin admin) {
        //1.根据用户名查用户
        Admin adminDB = adminDao.findByUserName(admin.getUsername());
        //2.判断用户名是否存在
        if(ObjectUtils.isEmpty(adminDB)){ throw new RuntimeException("用户名错误!");}
        //3.判断密码
        String password = DigestUtils.md5DigestAsHex(admin.getPassword().getBytes(StandardCharsets.UTF_8));
        if(!StringUtils.equals(password,adminDB.getPassword())){throw new RuntimeException("密码输入错误!");}
        return adminDB;
    }
    
}

上边这个是service层,下边这个是mapper文件代码

 <!--根据用户名查用户-->
    <select id="findByUserName"  parameterType="String" resultMap="AdminMap">
        select id,
               username,
               password,
               avatar,
               created_at,
               updated_at,
               deleted_at
        from yingxue.admin
        where username = #{username}
    </select>

不懂的地方的一些解释。

redisTemplate.setKeySerializer(new StringRedisSerializer());

redisTemplate.opsForValue().set(token,adminDB,30, TimeUnit.MINUTES)

上边第一句是设置序列化的方式,默认序列化会造成乱码。

第二句是设置的key-string类型,key为token,value为序列化后的admin对象(不止包括账号、密码,还有头像创建时间之类的)。

现在还有一个重要的问题,本题验证登录时用的sessionId作为token,然后把token给返回给浏览器了,有每次访问都得带着这个token来访问。这种做法是算session呢还是token呢,如果是算token的话,为啥用seessionId当token呢。

这里首先我们来看一下cookie、session和token的区别:

cookie和session是一种 追踪 \**客户端\**\**服务器端\**通信的一种方式。

cookie是通过在客户端记录信息(在服务端没有记录)确定用户身份的,而session则通过在服务器端记录信息确定用户身份。

cookie:在客户端请求服务器时,如果服务器需要记录该用户状态就生成一个cookie返回发给客户端的,有客户端浏览器保存cookie,当浏览器再请求该网站时,
浏览器把请求的网址和请求头里的cookie一同提交给服务器 标明自己用户身份和状态。cookie以一段 存储在浏览器中 的文本存在(但服务器中没有保存,所以不够安全
session : 避免浏览器中可能伪造cookie的不安全,所以 生成并存储 在服务器端的值, 当用户第一次访问服务器时,session在服务器中生成记录并保存,
然后将这个记录通过cookie返回给浏览器,浏览器下次访问时带上cookie,服务器再通过session验证传过来的cookie是否正确。session在用户第一次访
问服务器的时候自动创建。session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,超时未更新会失效。

注意:cookie是在浏览器端设置过期时间,session是在服务器端设置过期时间。

在session这个设计中,cookie保存的值本质上是什么呢,就是sessionId,每一个session独一无二的。

sessionid: HTTP协议是无状态的,session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为SESSIONID的cookie,
它的值为该Session的id。Session依据该cookie来识别是否为同一用户。用户第一次访问会产生一个记录,sessionId保存在session中。

session相比cookie更加安全,但是它还是有缺点,就是每一个用户连接都会在服务器端中产生一个sessionId,当用户很多时会导致服务器压力很大,另外当服务器有多台时还有考虑sessionid在这些服务器之间共享;为了解决这些问题就有了: token 。

当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。

token不保存在session中,服务端在生成token时,加入少量的用户信息,比如用户的id,我们对数据使用算法加密生成签名添加到token中(加密的密钥只有自己知道)传递给客户端,客户端下次访问时带上token,服务器端通过密钥解析token生成签名,比较两次签名是否相同,若不相同则验证失败

简单token的组成;uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token的前几位以哈希算法压缩成的一定长度的十六进制字符串。为防止token泄露)。

所以我们每次带的这个东西叫令牌,但是我们还是用token方式来实现登录验证的,验证成功返回请求数据,验证失败让用户重新登录。

 二、用户信息接口

即登录成功以后的主界面需要展示用户信息,比如账号、密码、头像等。

这个就简单了,直接传入token,然后再redis中让token做key得到value即可,value即Admin对象,这个接口就很简单了。

   /**
     * 已登录用户信息接口
     */
    @GetMapping("admin-user")
    public Admin admin(String token){
        log.info("当前token信息为:{}",token);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return (Admin) redisTemplate.opsForValue().get(token);
    }

其实为了redis中查看数据更清晰,其实redis存储token时可以加个前缀“TOKEN_”,这个东西可以抽离出来作为一个常量,然后放到common中。

三、登出接口

redis中删除相关token即可。

 

posted @ 2022-12-24 23:47  一直学习的程序小白  阅读(50)  评论(0编辑  收藏  举报