Java簡(jiǎn)易登錄注冊(cè)功能實(shí)現(xiàn)代碼解析
哈希算法(Hash)又稱摘要算法(Digest),它的作用是:對(duì)任意一組輸入數(shù)據(jù)進(jìn)行計(jì)算,得到一個(gè)固定長(zhǎng)度的輸出摘要。
哈希算法最重要的特點(diǎn)就是:
- 相同的輸入一定得到相同的輸出;
- 不同的輸入大概率得到不同的輸出。
- 哈希算法的目的就是為了驗(yàn)證原始數(shù)據(jù)是否被篡改。
我們來(lái)簡(jiǎn)單實(shí)現(xiàn)一個(gè)用于用戶注冊(cè)和登錄最基本的功能。
在登錄中,要檢查是否存在某個(gè)用戶信息,每個(gè)用戶信息都是唯一的,所以可以借助Set的特性來(lái)操作用戶信息的存放。
在注冊(cè)中,要檢查用戶名是否已經(jīng)被注冊(cè),而每個(gè)用戶名也是唯一的,所以在這里也利用Set來(lái)操作用戶名的存放。
當(dāng)然,也可以用Map來(lái)存放用戶名和用戶密碼,K存放用戶名,對(duì)應(yīng)的V存放密碼。但是為了讓用戶名和密碼的關(guān)聯(lián)度盡可能的小一些,所以利用兩個(gè)Set來(lái)分別存放用戶名和用戶信息。
由于Set是無(wú)序的,所以當(dāng)黑客獲取到這兩個(gè)數(shù)據(jù)文件的時(shí)候也很難將用戶名對(duì)應(yīng)到相應(yīng)的用戶信息。
這里的用戶信息指的是將用戶名和密碼混合后的信息,例如某個(gè)用戶的信息是"admin",密碼是"password",那么可以將這兩個(gè)字段混合來(lái)達(dá)到增長(zhǎng)信息量的目的。
當(dāng)然,為了讓安全性更高,可以利用特定的排列組合將兩個(gè)字符串混合,比如可以將兩個(gè)字符串拆解成字符數(shù)組,按照數(shù)組下標(biāo)的奇偶數(shù)來(lái)排列兩個(gè)字符串。
例如"admin"的長(zhǎng)度小于"password",因此以"admin"為基準(zhǔn),'a'為起始,"admin"占奇數(shù)位,"passw"占偶數(shù)位,剩余字符連接在生成字段后,即"apdamsisnword",就像把用戶名插入到了密碼中。
還有一種方法是對(duì)每個(gè)生成的用戶信息添加隨機(jī)字符,這個(gè)方法被稱為“加鹽”。
例如,用戶名和密碼依然是"admin"和"password",我們?cè)O(shè)置一個(gè)隨機(jī)salt = "aRandomSalt",然后將這個(gè)salt加入到用戶名和密碼之中,比如"admin" + salt + "password",salt + "admin" + "password"或是其他更復(fù)雜的組合。
后續(xù)的代碼中,簡(jiǎn)單的將用戶名和密碼連接在了一起,即"adminpassword"
package service; import java.math.BigInteger; import java.security.MessageDigest; import java.util.HashSet; import java.util.Set; import dao.Dao; // 儲(chǔ)存相關(guān)配置文件 import dao.UserInfoDao; // 用于將用戶信息存盤 import entity.UserInfo; // 用戶信息實(shí)體類,其中的兩個(gè)類成員是userName和userPassword,即用戶名和密碼 public class UserInfoService extends Dao { private String userInfoPath; // 用戶信息保存的文件路徑 private String userNamePath; // 用戶名保存的文件路徑 private UserInfoDao dao = new UserInfoDao(); public UserInfoService() { super(); userInfoPath = super.getResource().getString("userInfo"); userNamePath = super.getResource().getString("userName"); } /** * 用戶登錄。若用戶信息存在,則登錄成功;若用戶信息不存在,則登錄失敗 * * @param userInfo * @return 提示信息 */ public String userSignIn(UserInfo userInfo) { Set<String> userInfoSet = null; String tips; userInfoSet = dao.readInfo(userInfoPath); // 從相關(guān)文件中讀取用戶信息 if (userInfoSet == null) { // 若尚無(wú)用戶注冊(cè),則new HashSet<String>(),避免NullPointerException userInfoSet = new HashSet<String>(); } if (userInfoSet.contains(getUserInfoHashCode(userInfo))) { // 判斷是否含有相關(guān)用戶信息 tips = "登錄成功!"; } else { tips = "登錄失??!請(qǐng)檢查用戶名或密碼"; } return tips; } /** * 用戶注冊(cè)。若用戶名不存在,則注冊(cè)成功;若用戶名存在,則注冊(cè)失敗 * * @param userInfo * @return 提示信息 */ public String userSignUp(UserInfo userInfo) { Set<String> userInfoSet = null; Set<String> userNameSet = null; String tips; userInfoSet = dao.readInfo(userInfoPath); // 從相關(guān)文件中讀取用戶信息 userNameSet = dao.readInfo(userNamePath); // 從相關(guān)文件中讀取用戶名 if (userInfoSet == null) { // 若尚無(wú)用戶注冊(cè),則new HashSet<String>(),避免NullPointerException userInfoSet = new HashSet<String>(); } if (userNameSet == null) { // 若尚無(wú)用戶注冊(cè),則new HashSet<String>(),避免NullPointerException userNameSet = new HashSet<String>(); } if (userNameSet.add(userInfo.getUserName())) { // 判斷用戶名是否已注冊(cè) userInfoSet.add(getUserInfoHashCode(userInfo)); // 若用戶名未注冊(cè),則將用戶信息添加至Set中 dao.saveInfo(userInfoSet, userInfoPath); // 保存用戶信息到相關(guān)文件 dao.saveInfo(userNameSet, userNamePath); // 保存用戶名到相關(guān)文件 tips = "注冊(cè)成功!"; } else { tips = "注冊(cè)失??!用戶已存在"; } return tips; } /** * 以預(yù)設(shè)算法SHA-1加密用戶名和密碼,以預(yù)設(shè)基數(shù)36位保存 * * @param userInfo * @return 加密后的用戶信息 */ public String getUserInfoHashCode(UserInfo userInfo) { return getUserInfoHashCode(userInfo, "SHA-1", 36); // 用SHA-1算法生成用戶信息密鑰,進(jìn)制為36進(jìn)制 } /** * 以指定算法algorithm加密用戶名和密碼,以指定基數(shù)radix長(zhǎng)度保存 * * @param userInfo * @param algorithm * @param radix * @return 加密后的用戶信息 */ public String getUserInfoHashCode(UserInfo userInfo, String algorithm, int radix) { try { MessageDigest md = MessageDigest.getInstance(algorithm); // 用指定算法algorithm創(chuàng)建一個(gè)MessageDigest實(shí)例 md.update((userInfo.getUserName() + userInfo.getUserPassword()).getBytes("UTF-8")); // 將用戶名和密碼合并,調(diào)用update()輸入數(shù)據(jù) byte[] res = md.digest(); // 將摘要存放在byte[]中 return new BigInteger(1, res).toString(radix); // 返回一個(gè)指定進(jìn)制基數(shù)為radix的字符串 } catch (Exception e) { e.printStackTrace(); return ""; // 若異常則返回空字符串 } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java基于IO流實(shí)現(xiàn)登錄和注冊(cè)功能
- Java實(shí)現(xiàn)登錄與注冊(cè)頁(yè)面
- javaweb實(shí)現(xiàn)注冊(cè)登錄頁(yè)面
- JavaWeb實(shí)現(xiàn)用戶登錄注冊(cè)功能實(shí)例代碼(基于Servlet+JSP+JavaBean模式)
- Java+mysql用戶注冊(cè)登錄功能
- JAVA簡(jiǎn)單實(shí)現(xiàn)MD5注冊(cè)登錄加密實(shí)例代碼
- Servlet+JavaBean+JSP打造Java Web注冊(cè)與登錄功能
- JavaWeb簡(jiǎn)單用戶登錄注冊(cè)實(shí)例代碼(有驗(yàn)證碼)
- Java簡(jiǎn)易登錄注冊(cè)小程序
- Java使用IO模擬注冊(cè)登錄
相關(guān)文章
springboot如何通過(guò)session實(shí)現(xiàn)單點(diǎn)登入詳解
單點(diǎn)登錄(SSO)的定義是在多個(gè)應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問(wèn)所有相互信任的應(yīng)用系統(tǒng),下面這篇文章主要給大家介紹了關(guān)于springboot如何通過(guò)session實(shí)現(xiàn)單點(diǎn)登入的相關(guān)資料,需要的朋友可以參考下2021-12-12Java的動(dòng)態(tài)代理模式之JDK代理詳解
這篇文章主要介紹了Java的動(dòng)態(tài)代理模式之JDK代理詳解,代理對(duì)象,不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象要實(shí)現(xiàn)接口,否則不能用動(dòng)態(tài)代理,JDK?實(shí)現(xiàn)代理只需要使用?newProxyInstance?方法,但是該方法需要接收三個(gè)參數(shù),需要的朋友可以參考下2023-11-11Spring Boot項(xiàng)目使用Flyway的詳細(xì)教程
這篇文章主要介紹了Spring Boot項(xiàng)目使用Flyway,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07SpringCLoud搭建Zuul網(wǎng)關(guān)集群過(guò)程解析
這篇文章主要介紹了SpringCLoud搭建Zuul網(wǎng)關(guān)集群過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03SpringMVC 攔截器不攔截靜態(tài)資源的三種處理方式方法
本篇文章主要介紹了SpringMVC 攔截器不攔截靜態(tài)資源的三種處理方式方法,詳細(xì)的介紹了三種方法,有興趣的可以了解一下。2017-01-01SpringBoot基于Minio實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳的實(shí)現(xiàn)
本文主要介紹了SpringBoot基于Minio實(shí)現(xiàn)分片上傳、斷點(diǎn)續(xù)傳的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08Spring Boot與Kotlin定時(shí)任務(wù)的示例(Scheduling Tasks)
這篇文章主要介紹了Spring Boot與Kotlin定時(shí)任務(wù)的示例(Scheduling Tasks),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03詳解PowerDesigner之CDM、PDM、SQL之間轉(zhuǎn)換
這篇文章主要介紹了詳解PowerDesigner之CDM、PDM、SQL之間轉(zhuǎn)換的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下2017-10-10強(qiáng)烈推薦IDEA提高開(kāi)發(fā)效率的必備插件
這篇文章主要介紹了強(qiáng)烈推薦IDEA提高開(kāi)發(fā)效率的必備插件,文中有非常詳細(xì)的圖文示例,對(duì)想要提高企業(yè)開(kāi)發(fā)效率的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04