[黑馬頭條]-登錄實現思路

需求分析

在黑馬頭條項目中,登錄有兩種方式:一種是用戶輸入賬號密碼后登錄,這種方式登陸后的權限很大,可以查看,也可以進行其他操作;另一種方式就是用戶點擊不登錄,以游客的身份進入系統,但是權限不足,只可以查看帖子等信息,無法評論點準收藏等操作。

表結構分析

關于app端用戶相關的內容較多,可以單獨設置一個庫leadnews_user:

登錄需要用到的是ap_user表,表結構如下:

-- auto-generated definition
create table ap_user
(id                         int unsigned auto_increment comment '主鍵'primary key,salt                       varchar(32)      null comment '密碼、通信等加密鹽',name                       varchar(20)      null comment '用戶名',password                   varchar(32)      null comment '密碼,md5加密',phone                      varchar(11)      null comment '手機號',image                      varchar(255)     null comment '頭像',sex                        tinyint unsigned null comment '0 男1 女2 未知',is_certification           tinyint unsigned null comment '0 未1 是',is_identity_authentication tinyint(1)       null comment '是否身份認證',status                     tinyint unsigned null comment '0正常1鎖定',flag                       tinyint unsigned null comment '0 普通用戶1 自媒體人2 大V',created_time               datetime         null comment '注冊時間'
)comment 'APP用戶信息表';

?表結構如下圖所示:

tinyint類型:占1個字節,不指定unsigned(非負數),值范圍(-128,127),指定了unsigned,值范圍(0,255)
tinyint通常表示小范圍的數值,或者表示true或false,通常值為0表示false,值為1表示true

項目中的持久層使用的mybatis-plus,一般都使用mybais-plus逆向生成對應的實體類

app_user表對應的實體類如下:

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 lombok.Data;import java.io.Serializable;
import java.util.Date;/*** <p>* APP用戶信息表* </p>** @author itheima*/
@Data
@TableName("ap_user")
public class ApUser implements Serializable {private static final long serialVersionUID = 1L;/*** 主鍵*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 密碼、通信等加密鹽*/@TableField("salt")private String salt;/*** 用戶名*/@TableField("name")private String name;/*** 密碼,md5加密*/@TableField("password")private String password;/*** 手機號*/@TableField("phone")private String phone;/*** 頭像*/@TableField("image")private String image;/*** 0 男1 女2 未知*/@TableField("sex")private Boolean sex;/*** 0 未1 是*/@TableField("is_certification")private Boolean certification;/*** 是否身份認證*/@TableField("is_identity_authentication")private Boolean identityAuthentication;/*** 0正常1鎖定*/@TableField("status")private Boolean status;/*** 0 普通用戶1 自媒體人2 大V*/@TableField("flag")private Short flag;/*** 注冊時間*/@TableField("created_time")private Date createdTime;}

這個實體類名為 ApUser ,是一個Java類,用于映射數據庫中的 ap_user 表,它包含了多個字段,如主鍵 id 、加密鹽 salt 、用戶名 name 、加密后的密碼 password 、手機號 phone 、用戶頭像 image 、性別 sex 、認證狀態 certification 、身份認證狀態 identityAuthentication 、賬戶狀態 status 、用戶類型 flag 以及注冊時間 createdTime ,其中 id 字段使用了MyBatis-Plus的 @TableId 注解來指定其為主鍵,并且設置為主鍵生成策略為自動增長,其他字段則使用 @TableField 注解來指定對應的數據庫列名,類中還使用了lombok的 @Data 注解來自動生成getter和setter方法,以及 serialVersionUID 來支持序列化,整個類實現了 Serializable 接口,以支持對象的序列化操作。

思路分析

Md5相同的密碼每次加密都一樣,不太安全,所以在項目開發中我們一般會使用加鹽來加強密碼,思路如下:首先,前端根據用戶名+密碼來注冊:

第一步:我們根據用戶生成salt,這是一個隨機的字符串用表中的salt來保存;

第二步:我們通過密碼+salt來組成新的密碼,經過md5加密后的密碼保存在表password字段中;

第三步:當前端發來請求,我們會先根據用戶名來數據庫中查詢用戶;如果用戶不為空,則取出salt的值和前端傳遞過來的密碼拼接成新的密碼;然后再跟數據庫中的密碼比對,如果二者密碼一致,則用戶驗證成功;相反,如果比對不一致,則表示密碼有誤。

第四步:如果用戶是首次登錄的話,也就是是注冊的話,后端是需要生成一個jwt令牌給前端的,前端將這個令牌保存好;之后前端的每一次請求,都需要攜帶這個令牌;在后端根據令牌是否存在并且令牌是否有效來判斷請求是否可以正常執行。

用戶游客登錄,生成jwt返回(基于默認值0生成),當然這種方式登錄?的權限沒有賬號密碼登錄的權限大,游客登錄一般只有查看操作。

運營端微服務搭建

首先需要創建工程,在heima-leadnews-service下創建工程heima-leadnews-user,創建好之后需要建立對應的包,如圖所示:

引導類

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.user.mapper")
public class UserApplication {public static void main(String[] args) {SpringApplication.run(UserApplication.class,args);}
}

?這個引導類名為 UserApplication ,它是一個Spring Boot應用的啟動類,使用了 @SpringBootApplication 注解來標識這是一個Spring Boot應用,并且包含了 @EnableAutoConfiguration 、 @ComponentScan 和 @Configuration 等注解的功能,用于自動配置Spring應用上下文和組件掃描。此外,它還使用了 @EnableDiscoveryClient 注解來啟用Spring Cloud的客戶端發現功能,這使得應用能夠注冊到服務發現中心,從而實現微服務架構中的服務發現。 @MapperScan 注解用于指定MyBatis的Mapper接口所在的包路徑,以便Spring Boot自動掃描并注冊這些Mapper接口。在 main 方法中,通過調用 SpringApplication.run 方法并傳入當前類和命令行參數,來啟動Spring Boot應用。這個類是整個應用的入口點,通過運行這個類,就可以啟動整個Spring Boot應用并使其參與到微服務架構中。

bootstrap.yml

server:port: 51801
spring:application:name: leadnews-usercloud:nacos:discovery:server-addr: 192.168.200.130:8848config:server-addr: 192.168.200.130:8848file-extension: yml

在nacos中創建配置文件

代碼如下:

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: root
# 設置Mapper接口所對應的XML文件位置,如果你在Mapper接口中有自定義方法,需要進行該配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 設置別名包掃描路徑,通過該屬性可以給包中的類注冊別名type-aliases-package: com.heima.model.user.pojos

logback.xml

<?xml version="1.0" encoding="UTF-8"?><configuration><!--定義日志文件的存儲地址,使用絕對路徑--><property name="LOG_HOME" value="e:/logs"/><!-- Console 輸出設置 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern><charset>utf8</charset></encoder></appender><!-- 按照每天生成日志文件 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件輸出的文件名--><fileNamePattern>${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.log</fileNamePattern></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 異步輸出 --><appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"><!-- 不丟失日志.默認的,如果隊列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日志 --><discardingThreshold>0</discardingThreshold><!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --><queueSize>512</queueSize><!-- 添加附加的appender,最多只能添加一個 --><appender-ref ref="FILE"/></appender><logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false"><appender-ref ref="CONSOLE"/></logger><logger name="org.springframework.boot" level="debug"/><root level="info"><!--<appender-ref ref="ASYNC"/>--><appender-ref ref="FILE"/><appender-ref ref="CONSOLE"/></root>
</configuration>

登錄功能實現

①:接口定義

@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {@PostMapping("/login_auth")public ResponseResult login(@RequestBody LoginDto dto) {return null;}
}

?②:持久層mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.user.pojos.ApUser;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {
}

③:業務層service

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.LoginDto;
import com.heima.model.user.pojos.ApUser;public interface ApUserService extends IService<ApUser>{/*** app端登錄* @param dto* @return*/public ResponseResult login(LoginDto dto);}

實現類:

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserService;
import com.heima.utils.common.AppJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;import java.util.HashMap;
import java.util.Map;@Service//標記為服務類
@Transactional//保證了事務的原子性
@Slf4j//方便了記錄日志
//這段代碼的主要功能是實現用戶登錄和游客登錄的邏輯
//用戶登錄時,根據手機號查詢用戶,驗證密碼后返回用戶的JWT令牌和用戶信息
//游客登錄時,返回id為0的游客JWT令牌
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {@Overridepublic ResponseResult login(LoginDto dto) {//1.正常登錄(手機號+密碼登錄),如果前端傳遞的手機號和密碼都不為空的話,執行以下操作if (!StringUtils.isBlank(dto.getPhone()) && !StringUtils.isBlank(dto.getPassword())) {//1.1查詢用戶,使用MyBatis Plus的getOne方法查詢數據庫中phone字段與dto.getPhone()相同的用戶信息ApUser apUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));//先對從數據庫中查詢的對象進行判斷,為空表示數據庫沒有登陸者信息,直接結束方法if (apUser == null) {//用統一封裝結果集封裝結果,返回提示給用戶return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用戶不存在");}//1.2 比對密碼//獲取數據庫用戶的鹽String salt = apUser.getSalt();//獲取前端傳遞過來的代碼String pswd = dto.getPassword();//將上述兩個變量進行字符串拼接,然后再md5加密,賦值給pswdpswd = DigestUtils.md5DigestAsHex((pswd + salt).getBytes());//判斷我們剛剛生成的密碼和數據庫中的密碼是否一致if (!pswd.equals(apUser.getPassword())) {//不一致的話,通過統一封裝結果集封裝登錄密碼錯誤的信息會前端return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);}//密碼比對成功,就需要給用戶生成jet令牌//1.3 返回數據  jwtMap<String, Object> map = new HashMap<>();//用自定義的工具類AppJwtUtil給登錄用戶的id生成tokenmap.put("token", AppJwtUtil.getToken(apUser.getId().longValue()));//下面這兩步是是為了保護用戶隱私設置的,即將鹽和密碼置空,前端就查看不了密碼//然后再將當前用戶存入map集合中apUser.setSalt("");apUser.setPassword("");map.put("user", apUser);//最后,用統一封裝結果集將map集合返回給前端return ResponseResult.okResult(map);} else {//2.游客登錄,即沒有賬號密碼  同樣返回token  id = 0//我們約定如果是游客登錄的話,直接使用0作為用戶的id,生成tokenMap<String, Object> map = new HashMap<>();map.put("token", AppJwtUtil.getToken(0l));//直接將生成的token返回給前端展示return ResponseResult.okResult(map);}}
}

④:控制層controller

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.LoginDto;
import com.heima.user.service.ApUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {@Autowiredprivate ApUserService apUserService;@PostMapping("/login_auth")public ResponseResult login(@RequestBody LoginDto dto) {return apUserService.login(dto);}
}

思路分析:

這段代碼實現了一個用戶登錄服務,其中包括正常用戶登錄和游客登錄兩種情況。對于正常用戶登錄,首先檢查前端傳遞的手機號和密碼是否都不為空,然后使用MyBatis Plus的查詢方法根據手機號查詢數據庫中的用戶信息,如果用戶不存在則返回錯誤提示;如果用戶存在,則進一步比對密碼,通過將前端密碼與數據庫中的鹽值拼接后進行MD5加密,與數據庫中的密碼進行比較,如果密碼錯誤則返回錯誤提示;密碼正確則生成JWT令牌,并將用戶的敏感信息(鹽和密碼)置空后,連同令牌一起返回給前端。對于游客登錄,直接生成一個id為0的JWT令牌并返回。整個過程中,使用了 @Transactional 注解來保證事務的原子性,使用 @Slf4j 注解來方便日志記錄,同時通過自定義的工具類 AppJwtUtil 來生成JWT令牌,通過統一封裝的結果集 ResponseResult 來返回操作結果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89673.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89673.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89673.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

了解.NET Core狀態管理:優化技巧與常見問題解決方案

前言 歡迎關注dotnet研習社&#xff0c;今天我們聊聊“ .NET Core 中的狀態管理”。 在Web應用程序中&#xff0c;管理和維持狀態是一個非常重要的主題&#xff0c;尤其是在無狀態的環境中&#xff0c;如 HTTP 協議和 RESTful API。對于基于 .NET Core 構建的應用程序&#xff…

504網關超時可能是哪些原因導致?

在網絡訪問中&#xff0c;504 網關超時&#xff08;Gateway Timeout&#xff09;如同一個突然亮起的警示燈&#xff0c;打斷用戶的瀏覽或操作流程。這個 HTTP 狀態碼意味著服務器作為網關或代理時&#xff0c;未能在規定時間內收到上游服務器的響應。引發504錯誤的核心因素有哪…

ComfyUI 常見報錯問題解決方案合集(持續更新ing)

前言&#xff1a; 本文匯總了 5 大高頻問題 及其解決方案&#xff0c;涵蓋&#xff1a; HuggingFace 認證修復&#xff08;Token 申請 手動下載指南&#xff09; ComfyUI 版本更新&#xff08;完整命令 依賴管理&#xff09; 自啟動配置&#xff08;Conda 環境 權限修復&…

完美解決Linux服務器tomcat開機自啟動問題

經過多次測試終于徹底解決tomcat開機自啟動的問題了 PID3ps aux | grep /home/server/shichuan/ | grep java | awk {print $2} if [ -n "$PID3" ]; then 這個判斷pid的方式還是可能出現啟動失敗的情況 # tail -n 1 /home/server/shichuan/logs/catalina.out |grep…

kotlin部分常用特性總結

<h3>Kotlin中類和對象初始化</h3><ul> <li>添加open關鍵字代表可以被繼承</li> <li>Any 是所有類的父類,類似Object,包含 equals() hashCode() toString()方法</li> <li>constructor 關鍵字代表構造函數, constructor關鍵字可…

PHP 就業核心技能速查手冊

# PHP 就業核心技能速查手冊 > 高效聚焦市場所需&#xff0c;快速提升競爭力 --- ## 一、語法基礎&#xff08;必會&#xff01;&#xff09; php // 1. 變量與數據類型 $price 19.99; // 浮點型 $isStock true; // 布爾型 // 2. 流程控制 foreach ($…

從混沌到秩序:數據科學的熱力學第二定律破局——線性回歸的熵減模型 × 最小二乘的能量最小化 × 梯度下降的負反饋控制系統,用物理定律重構智能算法的統一場論

目錄 一、機器學習是什么&#xff1f; 1.1 什么是機器學習&#xff1f; 1.2 機器學習的三大類型 二、線性回歸是什么&#xff1f; 2.1 通俗理解 2.2 數學表達 三、最小二乘法&#xff08;Least Squares Method&#xff09; 3.1 什么是損失函數&#xff1f; 3.2 什么是最小…

BI 數據可視化平臺建設(3)—首頁性能提升實踐

作者&#xff1a; vivo 互聯網大數據團隊- Wang Lei 本文是vivo互聯網大數據團隊《BI 數據可視化平臺建設》系列文章第3篇。 隨著越來越多代碼的堆積&#xff0c;平臺的運行加載性能也在逐步下降&#xff0c;在不同程度上極大地影響了用戶體驗&#xff0c;從而導致用戶流失。本…

基于Python的畢業設計選題管理系統設計與實現

基于Python的畢業設計選題管理系統設計與實現摘要本論文詳細闡述了一個基于Python的畢業設計選題管理系統的設計與實現過程。該系統采用了Python的Tkinter庫構建圖形用戶界面&#xff0c;使用SQLite數據庫存儲數據&#xff0c;實現了高校畢業設計選題過程中的教師出題、學生選題…

如何在HTML5頁面中嵌入視頻

在HTML5中嵌入視頻主要使用<video>標簽&#xff0c;這是一種簡單且標準的方式。以下是詳細步驟和示例&#xff1a; 基礎實現 <!DOCTYPE html> <html> <head><title>視頻嵌入示例</title> </head> <body><!-- 基礎視頻播放器…

java操作Excel兩種方式EasyExcel 和POI

一、POI1.引入依賴<!-- 03 xls--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.9</version> </dependency><!-- 07 xlsx --> <dependency><groupId>org.a…

Openlayers 面試題及答案180道(141-160)

《前后端面試題》專欄集合了前后端各個知識模塊的面試題,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。 前后端面試題-專欄總目錄 文章目錄 一、本文面試題目錄 141. 如何在生產環境中優…

LangChain面試內容整理-知識點24:實戰案例:智能助手 Agent 構建

本案例講述如何用LangChain構建一個結合多個工具的智能助手 Agent。智能助手需要理解用戶復雜請求,通過調用不同工具(如搜索、計算、查數據庫等)執行多步推理,再給出答案。LangChain的Agent框架非常適合這種場景。 構建步驟: 確定需求和選擇Agent類型:假設我們要一個能上…

【MATLAB例程】Taylor算法用于TOA(到達時間)的三維標簽位置解算,可自適應基站數量。附下載鏈接

本文給出自適應錨點&#xff08;基站&#xff09;的Taylor算法解算TOA&#xff08;到達時間&#xff09;的MATLAB代碼。參考論文&#xff1a;《基于Taylor-Chan算法的改進UWB室內三維定位方法》中的Taylor算法來解算TOA的復現程序&#xff08;MATLAB&#xff09;。 文章目錄運行…

Eclipse代碼折疊增強插件的安裝與使用

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;Eclipse作為Java開發者的IDE&#xff0c;提供包括代碼折疊在內的多種功能&#xff0c;便于管理與閱讀代碼。本文介紹的“com.cb.eclipse.folding_1.0.6.jar”插件能夠進一步增強Eclipse的代碼折疊能力。安裝后&…

Python day18

浙大疏錦行 python day 18. 內容&#xff1a; 昨天學習了聚類算法的一些基本內容&#xff0c;今天繼續學習相關知識分析簇的特征和相關含義&#xff08;使用可視化來進行分析&#xff0c;也可以使用ai&#xff09; 代碼&#xff1a; shap.initjs() # 初始化 SHAP 解釋器 ex…

WPS文檔中心及文檔中臺遠程命令執行漏洞

【嚴重】WPS文檔中心及文檔中臺遠程命令執行漏洞 漏洞描述 WPS文檔中心是面向個人和企業的云端文檔存儲與管理平臺&#xff0c;WPS文檔中臺是為企業提供的集成化文檔協同與流程管理解決方案&#xff0c;強調API對接與業務系統整合。 在2024年5月之前通過docker私有化部署的版…

WPF 加載和顯示 GIF 圖片的完整指南

WPF 加載和顯示 GIF 圖片的完整指南 在 WPF 中加載和顯示 GIF 圖片需要一些特殊處理&#xff0c;因為 WPF 的 Image 控件默認不支持動畫 GIF。 解決方案一&#xff1a;使用 WpfAnimatedGif 庫&#xff08;推薦&#xff09; 這是最簡單且功能最完整的方法。 實現步驟&#xff1a…

Node.js GET/POST請求詳解

Node.js GET/POST請求詳解 引言 Node.js作為一種基于Chrome V8引擎的JavaScript運行環境&#xff0c;以其高性能、非阻塞I/O模型和輕量級等特點&#xff0c;在服務器端開發中得到了廣泛應用。本文將詳細介紹Node.js中GET和POST請求的處理方法&#xff0c;幫助開發者更好地理解和…

C++string類(2)

3.string類對象的訪問及遍歷操作函數名稱功能說明operator[] &#xff08;重 點&#xff09;返回pos位置的字符&#xff0c;const string類對象調用beginendbegin獲取第一個字符的迭代器 end獲取最后一個字符下一個位置的迭代器rbeginrendrbegin獲取最后一個字符的迭代器 ren…