登录和退出(五)

主要流程入下:

  • 访问登录页面
    • 点击顶部区域内的链接,打开登录页面。
  • 登录
    • 验证账号、密码、验证码。
    • 成功时,生成登录凭证,发放给客户端。
    • 失败时,跳转回登录页。
  • 退出
    • 将登录凭证修改为失效状态。
    • 跳转至网站首页。

一、访问登录页面

控制层代码入下。

    @GetMapping("/login")
    public String getLoginPage() {
        return "/site/login";
    }

登录界面入下。

二、登录功能

登录功能,在服务端验证账号、密码、验证码。成功时,服务端生成登录凭证,并将其发送给客户端。失败时,则跳转到回登录页面。

1.编写Mapper代码

登录凭证类LoginTicket入下,由MybatisX自动生成。

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;

/**
 * 
 * @TableName login_ticket
 */
@TableName(value ="login_ticket")
@Data
public class LoginTicket implements Serializable {
    /**
     * id
     */
    @TableId(type = IdType.AUTO)
    private Integer id;

    /**
     * 用户
     */
    private Integer userId;

    /**
     * 登录凭证
     */
    private String ticket;

    /**
     * 0-有效; 1-无效;
     */
    private Integer status;

    /**
     *  到期时间
     */
    private Date expired;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

LoginTicketMapper接口入下,其实可也可不定义方法,Mybatis plus自带的方法足够。

import com.nowcoder.community.entity.LoginTicket;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Update;

/**
 * @Entity com.nowcoder.community.entity.LoginTicket
 */
public interface LoginTicketMapper extends BaseMapper<LoginTicket> {
    //通过登录凭证更新状态
    @Update({
            "update login_ticket set status = #{status} where ticket = #{ticket}"
    })
    int updateStatus(String ticket, int status);
}

2.编写业务层代码

    /**
     * 登录
     *
     * @param username       用户名
     * @param password       密码
     * @param expiredSeconds 过期时间(秒)
     * @return
     */
    public Map<String, Object> login(String username, String password, int expiredSeconds) {
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isBlank(username)) {
            map.put("usernameMsg", "账号不能为空!");
            return map;
        }
        if (StringUtils.isBlank(password)) {
            map.put("passwordMsg", "密码不能为空");
            return map;
        }
        //查询账号
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getUsername, username);
        User user = getOne(lqw);
        //验证账号
        if (user == null) {
            map.put("usernameMsg", "该账号不存在!");
            return map;
        }
        //验证状态
        if (user.getStatus() == 0) {
            map.put("usernameMsg", "该账号未激活!");
            return map;
        }
        //验证密码
        password = CommunityUtils.md5(password + user.getSalt());
        if (!password.equals(password)) {
            map.put("passwordMsg", "密码错误!");
            return map;
        }
        //生成登录凭证
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        loginTicket.setTicket(CommunityUtils.generateUUID());
        loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
        loginTicketMapper.insert(loginTicket);
        map.put("ticket", loginTicket.getTicket());
        return map;
    }

3.编写控制层代码

    @PostMapping("/login")
    public String login(String username, String password, String code, boolean rememberme,
                        Model model, HttpSession session, HttpServletResponse response) {
        // 检查验证码
        String kaptcha = (String) session.getAttribute("kaptcha");
        if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
            model.addAttribute("codeMsg", "验证码不正确!");
            return "/site/login";
        }
        //设置超时时间
        int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
        //检查账号密码
        Map<String, Object> map = userService.login(username, password, expiredSeconds);
        //成功
        if (map.containsKey("ticket")) {
            //将登录凭证放到cookie中
            Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
            cookie.setPath(contextPath);
            //设置有效时间
            cookie.setMaxAge(expiredSeconds);
            //发送给页面
            response.addCookie(cookie);
            return "redirect:/index";
        } else { //失败
            model.addAttribute("usernameMsg", map.get("usernameMsg"));
            model.addAttribute("passwordMsg", map.get("passwordMsg"));
            return "/site/login";
        }
    }

cookie中的登录凭证入下:
image
数据库中的登录凭证入下,二者保持一致
image

三、退出功能

退出功能,在点击退出链接时将登录凭证改为失效状态,并跳转到网站首页。

业务层,修改登录凭证状态,使其失效

    /**
     * 退出
     * @param ticket 登录凭证
     */
    public void logout(String ticket) {
        loginTicketMapper.updateStatus(ticket, 1);
    }

控制层,返回到登录界面

    @GetMapping("/logout")
    public String logout(@CookieValue("ticket") String ticket) {
        userService.logout(ticket);
        return "redirect:/login";
    }

修改后的登录凭证。
image

posted @   DaleLee  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示