# 问题
最初,我建立 Hexo 博客的原因仅仅是觉得创建一个学习用的博客很酷,而且有成就感。不过,我并不想把博客公开,只想自己看看,自己琢磨。因此,一开始我并没有将博客托管到网上。然而,随着时间的推移,我发现每次打开本地博客都太麻烦,而且只能在建立博客的那台电脑上查看,实在不方便。于是,我先后将博客托管到了 Gitee Pages 和 GitHub Pages(在 Gitee 官方取消该功能后,我就不再使用了)。
托管到 GitHub 后,虽然可以随时随地登录查看博客,但因为有些内容写得太羞耻,我仍然担心被外人偶然看到(尽管这种可能性微乎其微)。作为一名搭建网站的外行爱好者,我一直在寻找方便的保密方法。
一开始我使用的是 hexo-blog-encrypt
插件来为博客的文章加密。然而,每篇文章都需要单独加密,打开时还需输入密码,而且有些内容(如图片)无法完全加载,每次都要刷新网页,这实在太麻烦了。后来,我考虑将博客放在阿里云等服务器上,设置一个加密登录,但作为外行,我完全无从下手,最终放弃了。
最近,我突发奇想地拷打了一下 ChatGPT,希望能找到简单的前端加密方法。令人惊喜的是,它真的给出了我满意的解决方案。
# 解决方案
在用户试图访问我的博客首页或者其他页面时,在每个页面加载的过程中,JavaScript 就会检查 localStorage
中是否存在 loggedIn
标志,若不存在则意味着用户尚未登录,用户会被重定向登录页面。用户在登录页面输入密码并提交表单,JavaScript 会将输入的密码与预设的正确密码进行比较。如果匹配,JavaScript 会在 localStorage
中设置 loggedIn
标志,并将用户重定向回首页。如果不匹配,则会提示用户密码错误。只有当用户成功登录( loggedIn
标志为 true
)后,才能访问博客的其他内容。
并且游览器会储存登录的状态,意味着我下一次用自己的电脑的同一个游览器打开,就不需要再输入密码了,这很方便。
# 解决问题的具体操作
- 创建登录页面
首先,在 hexo 的source
目录中创建一个新的 HTML 文件,命名为login.html
,内容如下:
<!DOCTYPE html> | |
<html lang="zh"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>登录</title> | |
<style> | |
body { | |
margin: 0; | |
display: grid; /* 使用 grid 布局 */ | |
place-items: center; /* 水平和垂直居中 */ | |
height: 100vh; | |
background-color: #ffeef8; | |
color: #d5006d; | |
font-family: Arial, sans-serif; | |
} | |
.login-container { | |
display: flex; /* 使用 flexbox */ | |
flex-direction: column; /* 垂直排列 */ | |
align-items: center; /* 水平居中 */ | |
background: rgba(255, 182, 193, 0.9); | |
padding: 20px; | |
border-radius: 10px; | |
width: 100%; /* 容器宽度占满整个页面 */ | |
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); | |
} | |
input { | |
text-align: center; /* 输入框内容居中 */ | |
font-size: 18px; | |
padding: 8px; | |
margin: 10px 0; | |
width: 100%; /* 输入框宽度占满 */ | |
border: 2px solid #d5006d; | |
border-radius: 5px; | |
outline: none; | |
} | |
button { | |
font-size: 18px; | |
padding: 8px; | |
width: 100%; /* 按钮宽度占满 */ | |
border: none; | |
border-radius: 5px; | |
cursor: pointer; | |
background: #d5006d; | |
color: white; | |
} | |
button:hover { | |
background: #c4005a; | |
} | |
#sidebar, .header, .footer { | |
display: none !important; /* 隐藏边栏、上栏和下栏 */ | |
} | |
</style> | |
</head> | |
<body> | |
<div class="login-container"> | |
<h1>要输入密码才能进入哦~~</h1> | |
<input type="password" id="password" placeholder="密码" onkeypress="checkEnter(event)"> | |
<button onclick="checkPassword()">link start!!!</button> | |
</div> | |
<script> | |
function checkPassword() { | |
const password = document.getElementById('password').value; | |
const correctPassword = '130'; // 设置你的密码 | |
if (password === correctPassword) { | |
localStorage.setItem('loggedIn', 'true'); | |
window.location.href = '/'; // 登录成功后重定向到首页 | |
} else { | |
alert('你的电波不对哦~~'); | |
} | |
} | |
function checkEnter(event) { | |
if (event.key === 'Enter') { | |
checkPassword(); // 按回车键时调用登录函数 | |
} | |
} | |
window.onload = function() { | |
if (localStorage.getItem('loggedIn') === 'true') { | |
window.location.href = '/'; // 已登录则跳转到首页 | |
} | |
} | |
</script> | |
</body> | |
</html> |
- 添加路由保护
在 hexo 的 主题文件的layout/_partial/header.njk
文件中添加下述代码,以便在每次访问博客时检查是否已登录:
<script> | |
window.onload = function() { | |
if (!localStorage.getItem('loggedIn')) { | |
window.location.href = '/login'; // 未登录时重定向到登录页面 | |
} | |
} | |
</script> |
- 添加路由映射
在_config.yml
中添加路由映射,使其更友好和简洁。可以按如下方式添加:
routes: | |
/login: /login.html |
这样也就完成了,是不是很简单!
# 目前的成品
目前的成品也就这样子,登录界面看起来还是比较丑的。等我以后有无聊的时间了,就再美化一下吧。
# 安全性注意事项
纵使这种加密方式我目前还算是比较满意的,但我也还是得清楚它的不安全性。其这种加密方式的原理可概况如下三点:
- 前端存储:使用
localStorage
在用户的浏览器中存储登录状态。这种方法简单,适合不涉及敏感信息的场景。 - JavaScript 验证:所有的密码验证和重定向都是在浏览器中通过 JavaScript 实现,不需要服务器端处理。这使得设置过程简单,但也意味着安全性较低。
- 无后端支持:此方法不依赖于任何服务器端代码或数据库,因此适合静态网站(如 GitHub Pages)。
由于密码是明文存储在代码中的,且通过浏览器进行验证,因此方式并不安全。用户完全可以通过开发者工具查看和修改 localStorage
。总的来说,这种方法适合于简单的访问控制,但不适合保护需要更高安全性的内容。如果是稍微有一些专业知识,或者是一些有心人士,想要破解这种保护措施并不难。若想要更高级的保护措施,则需要考虑更安全的身份验证机制,例如后端用户验证、数据库存储密码、使用 HTTPS 等方式。这些方法能提供更好的保护,防止未授权访问。
目前,我的博客内容并不包含敏感或机密的信息,主要是一些学习笔记和个人感想。虽然里面有一些个人信息,但我觉得即使被外人看到,也不会对我造成实质伤害,顶多会让我感到羞愧。如果有一天,我的博客中出现了需要保密的敏感内容,我会考虑采取更高级的安全保护措施的。