当前位置: 首页 > news >正文

尚庭公寓--------登陆流程介绍以及功能代码

登陆认证

基于Session的认证流程

优点

  1. 用户友好:
    • 用户登录后,无需在每个页面请求中重复输入用户名和密码。• 提供了一种无缝的用户体验,用户在浏览网站时不会频繁被要求重新认证。
  2. 安全性:
    • 服务器端维护用户状态信息,而客户端仅存储一个Session ID,这样可以减少敏感信息的暴露。
    • Session ID通常具有时效性,可以设置过期时间,增加了安全性。
  3. 易于管理:
    • 服务器可以轻松地管理用户会话,例如,可以控制Session的生命周期,包括创建、更新和销毁Session。
    • 可以对Session进行序列化,以便在服务器重启时恢复用户会话。
  4. 灵活性:
    • 可以存储用户特定的信息,如用户角色、权限等,以便在用户会话期间使用。
    • 可以根据需要自定义Session的行为,例如,可以设置Session的有效期、锁定机制等。
  5. 支持分布式部署:
    • 在分布式系统中,可以通过共享Session存储或使用Session复制技术来支持Session的一致性。
  6. 防止CSRF攻击:
    • 通过在Session中存储CSRF令牌,并在表单提交时验证令牌,可以有效地防止跨站请求伪造(CSRF)攻击。
    在这里插入图片描述

基于Token的认证流程

优点

  1. 无状态和可扩展性:
  2. • 基于Token的认证是无状态的,服务器不需要存储Session信息,这使得系统更容易扩展,特别是在分布式系统中。
  3. 安全性:
    • Token通常经过数字签名,这确保了Token在传输过程中未被篡改。
    • 可以使用强大的加密算法来生成Token,增加了安全性。
  4. 支持跨域认证:
    • 由于Token是自包含的,它可以在多个域之间安全地传递,这使得它非常适合单点登录(SSO)场景。
  5. 自定义性强:
    • Token可以包含丰富的用户信息和权限数据,这些信息可以根据需要进行定制。
  6. 减少服务器负担:
    • 由于服务器不需要存储Session信息,这减少了服务器的存储和内存负担。
  7. 支持移动和分布式设备:
    • Token可以在多种环境中使用,包括移动设备和分布式系统中,这使得它非常适合现代的移动和云应用。
  8. 简单易于实现:
    • 基于Token的认证流程相对简单,易于实现和维护。
    在这里插入图片描述

Token详解 :

Token是一种令牌,它在计算机身份验证中用于代表用户身份或会话。在Web开发中,Token通常用于用户认证和授权,尤其是在无状态的API服务和单点登录(SSO)系统中。以下是对Token的详细解释:

Token的组成

以JWT(JSON Web Tokens)为例,一个Token通常由三部分组成,用点(.)分隔:

- Header(头部):

• 描述Token的元数据,例如Token的类型(JWT)和使用的签名算法(如HMAC SHA256或RSA)。

- Payload(负载):

• 包含声明(Claims),即有关实体(通常是用户)和其他数据的声明。

• 可以包含用户的角色、权限、Token的发行者、过期时间等信息。

- Signature(签名):

• 用于验证Token在传输过程中未被篡改。

• 通过使用头部指定的算法和密钥对头部和负载进行签名生成。

Token的安全性

数字签名:

• 使用私钥对Token进行签名,确保Token的完整性和真实性。

加密:

• 使用对称或非对称加密算法对Token进行加密,确保只有授权的接收者才能解密和读取Token内容。

过期时间:

• 设置Token的过期时间,过期后Token将失效,需要重新认证获取新的Token。

HTTPS:

• 在传输过程中使用HTTPS,防止Token在传输过程中被截获。

尚庭公寓后台管理系统登陆流程

在这里插入图片描述
根据上述图片我们可以分析出总共需要完成三个接口,以下是接口定义以及接口代码

获取图形验证码

导入maven依赖

<dependency><groupId>com.github.whvcse</groupId><artifactId>easy-captcha</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置application.yml

spring:data:redis:host: <hostname>port: <port>database: 0

controller

package com.nie.lease.web.admin.controller.login;import com.nie.lease.common.login.LoginUserHolder;
import com.nie.lease.common.result.Result;
import com.nie.lease.common.utils.JwtUtils;
import com.nie.lease.web.admin.service.LoginService;
import com.nie.lease.web.admin.vo.login.CaptchaVo;
import com.nie.lease.web.admin.vo.login.LoginVo;
import com.nie.lease.web.admin.vo.system.user.SystemUserInfoVo;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@Tag(name = "后台管理系统登录管理")
@RestController
@RequestMapping("/admin")
public class LoginController {@Autowiredprivate LoginService service;@Operation(summary = "获取图形验证码")@GetMapping("login/captcha")public Result<CaptchaVo> getCaptcha() {CaptchaVo result=service.getCaptcha();return Result.ok(result);}

service接口

package com.nie.lease.web.admin.service;import com.nie.lease.web.admin.vo.login.CaptchaVo;
import com.nie.lease.web.admin.vo.login.LoginVo;
import com.nie.lease.web.admin.vo.system.user.SystemUserInfoVo;public interface LoginService {CaptchaVo getCaptcha();}

service实现类

    @Overridepublic CaptchaVo getCaptcha() {SpecCaptcha specCaptcha = new SpecCaptcha(130,  48,  4);String code = specCaptcha.text().toLowerCase();String key = RedisConstant.ADMIN_LOGIN_PREFIX  + UUID.randomUUID();stringRedisTemplate.opsForValue().set(key,code,RedisConstant.ADMIN_LOGIN_CAPTCHA_TTL_SEC, TimeUnit.SECONDS);return new CaptchaVo(specCaptcha.toBase64(),key);}

测试结果如下:
在这里插入图片描述
在这里插入图片描述

登录

导入maven依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId>
</dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><scope>runtime</scope>
</dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><scope>runtime</scope>
</dependency>
创建Jwt工具类
package com.nie.lease.common.utils;import com.nie.lease.common.exception.LeaseException;
import com.nie.lease.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;import javax.crypto.SecretKey;
import java.util.Date;public class JwtUtils {private static SecretKey tokenSignKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());public static String createToken(Long userId, String username) {String token = Jwts.builder().setSubject("USER_INFO").setExpiration(new Date(System.currentTimeMillis() + 3600000)).claim("userId", userId).claim("username", username).signWith(tokenSignKey).compact();return token;}public static void main(String[] args) {System.out.println(createToken(2L, "user"));}public static Claims  parseToken(String token){if (token==null){throw new LeaseException(ResultCodeEnum.ADMIN_LOGIN_AUTH);}try {JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(tokenSignKey).build();Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);return claimsJws.getBody();}catch (ExpiredJwtException e){throw new LeaseException(ResultCodeEnum.TOKEN_EXPIRED);}catch (JwtException e){throw new LeaseException(ResultCodeEnum.TOKEN_INVALID);}}
}
controller
    @Operation(summary = "登录")@PostMapping("login")public Result<String> login(@RequestBody LoginVo loginVo) {String token = service.login(loginVo);return Result.ok(token);}
service接口
    String login(LoginVo loginVo);
service实现类
    @Overridepublic String login(LoginVo loginVo) {//1.判断是否输入了验证码if (!StringUtils.hasText(loginVo.getCaptchaCode())) {throw new LeaseException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_NOT_FOUND);}//2.校验验证码String code = stringRedisTemplate.opsForValue().get(loginVo.getCaptchaKey());if (code == null) {throw new LeaseException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_EXPIRED);}if (!code.equals(loginVo.getCaptchaCode().toLowerCase())) {throw new LeaseException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_ERROR);}//3.校验用户是否存在SystemUser systemUser = systemUserMapper.selectOneByUsername(loginVo.getUsername());if (systemUser == null) {throw new LeaseException(ResultCodeEnum.ADMIN_ACCOUNT_NOT_EXIST_ERROR);}//4.校验用户是否被禁if (systemUser.getStatus() == BaseStatus.DISABLE) {throw new LeaseException(ResultCodeEnum.ADMIN_ACCOUNT_DISABLED_ERROR);}//5.校验用户密码if (!systemUser.getPassword().equals(DigestUtils.md5Hex(loginVo.getPassword()))) {throw new LeaseException(ResultCodeEnum.ADMIN_ACCOUNT_ERROR);}//6.创建并返回TOKENreturn JwtUtils.createToken(systemUser.getId(), systemUser.getUsername());}
mapper接口
SystemUser selectOneByUsername(String username);

mapperxml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.lease.web.admin.mapper.SystemUserMapper"><select id="pageSystemUser" resultType="com.nie.lease.web.admin.vo.system.user.SystemUserItemVo">select su.id,username,su.name,type,phone,avatar_url,additional_info,post_id,su.status,sp.name post_namefrom system_user suleft join system_post sp on su.post_id = sp.id and sp.is_deleted = 0<where>su.is_deleted = 0<if test="queryVo.name != null and queryVo.name != ''">and su.name like concat('%',#{queryVo.name},'%')</if><if test="queryVo.phone !=null and queryVo.phone != ''">and su.phone like concat('%',#{queryVo.phone},'%')</if></where></select><select id="selectOneByUsername" resultType="com.nie.lease.model.entity.SystemUser">select id,username,password,name,type,phone,avatar_url,additional_info,post_id,statusfrom system_userwhere is_deleted = 0and username = #{username}</select>
</mapper>
编写拦截器
书写解析token的方法
package com.nie.lease.common.utils;import com.nie.lease.common.exception.LeaseException;
import com.nie.lease.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;import javax.crypto.SecretKey;
import java.util.Date;public class JwtUtils {private static SecretKey tokenSignKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());public static String createToken(Long userId, String username) {String token = Jwts.builder().setSubject("USER_INFO").setExpiration(new Date(System.currentTimeMillis() + 3600000)).claim("userId", userId).claim("username", username).signWith(tokenSignKey).compact();return token;}public static void main(String[] args) {System.out.println(createToken(2L, "user"));}public static Claims  parseToken(String token){if (token==null){throw new LeaseException(ResultCodeEnum.ADMIN_LOGIN_AUTH);}try {JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(tokenSignKey).build();Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);return claimsJws.getBody();}catch (ExpiredJwtException e){throw new LeaseException(ResultCodeEnum.TOKEN_EXPIRED);}catch (JwtException e){throw new LeaseException(ResultCodeEnum.TOKEN_INVALID);}}
}

##### 编写拦截器

package com.nie.lease.web.admin.custom.interceptor;import com.nie.lease.common.exception.LeaseException;
import com.nie.lease.common.login.LoginUser;
import com.nie.lease.common.login.LoginUserHolder;
import com.nie.lease.common.result.ResultCodeEnum;
import com.nie.lease.common.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;@Component
public class AuthenticationInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("access-token");Claims claims = JwtUtils.parseToken(token);Long userId = claims.get("userId", Long.class);String userName = claims.get("userName", String.class);LoginUserHolder.setLoginUser(new LoginUser(userId, userName));return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {LoginUserHolder.clear();}
}
注册拦截器

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Autowiredprivate StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;@Autowiredprivate AuthenticationInterceptor authenticationInterceptor;@Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverterFactory(this.stringToBaseEnumConverterFactory);}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(this.authenticationInterceptor).addPathPatterns("/admin/**").excludePathPatterns("/admin/login/**");}}
http://www.dtcms.com/a/289413.html

相关文章:

  • 常见的离散积分方法
  • 基于bert-lstm对微博评论的情感分析系统设计与实现
  • 《每日AI-人工智能-编程日报》--2025年7月20日
  • Direct3D 11学习(一)
  • Charles 的 Windows proxy 对爬取瑞数6 网站接口数据的作用分析
  • 高性能架构模式——单服务器高性能模式(PPC与TPC)
  • 创新几何解谜游戏,挑战空间思维极限
  • 【51单片机仿真复位电阻电容参数】2022-5-17
  • TD3与SAC强化学习算法深度对比
  • BLIP、InternVL Series(下)
  • SSH开启Socks5服务
  • 强化学习_Paper_ICLR2024_When Should We Prefer DECISION TRANSFORMERS for offline-RL
  • 【分布式 ID】详解百度 uid-generator(基础篇)
  • java12基础(day12)
  • 零基础学习性能测试第一章-为什么会有性能问题
  • 【读技术报告】Manner Agent如何管理上下文
  • 从 AlphaGo 到具身机器人:AI 四力阶梯的突破之旅
  • 爬虫实战案例(两个)
  • Open64 WHIRL
  • `tidyverse` 长表、宽表的处理
  • 使用Qt6 QML/C++ 和CMake构建海康威视摄像头应用(代码开源)
  • 看板流程标准化和灵活性如何平衡
  • 在Ubuntu22系统上离线部署ai-infra-guard教程【亲测成功】
  • 深入分析linux内核源代码
  • PID控制原理分析及应用(稳态误差详细分析)(一)
  • 【高等数学】第四章 不定积分——第四节 有理函数的积分
  • 【LeetCode 热题 100】124. 二叉树中的最大路径和——DFS
  • [Python] -项目实战7- 用Python和Tkinter做一个图形界面小游戏
  • Servlet API 详解
  • 佛经个人阅读(二)《金刚经》解析