这一次使用纯粹使用前端来加密内容,优点是部署方便,不用折腾后端和数据库,缺点是加密不灵活,如果要修改密钥需要重新生成密文。
首先是加密代码,为了方便测试,同时加入了解密功能,你可以在本地打开这个html文件使用:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加密内容查看器</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
background: inherit;
}
.container {
width: 100%;
max-width: 100%;
padding: 20px;
box-sizing: border-box;
background: inherit;
}
.section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background: inherit;
}
textarea {
width: 100%;
height: 100px;
margin: 10px 0;
padding: 8px;
box-sizing: border-box;
border: 1px solid #ddd;
border-radius: 4px;
background: inherit;
}
input {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
margin-right: 10px;
font-size: 16px;
background: inherit;
}
button {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
.result {
margin-top: 20px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
word-break: break-all;
background: inherit;
}
.error {
color: #ff4444;
margin-top: 10px;
}
/* 响应式布局 */
@media screen and (max-width: 768px) {
body {
padding: 10px;
}
.container {
padding: 10px;
}
.section {
padding: 15px;
}
input {
width: 100%;
margin: 10px 0;
}
button {
width: 100%;
margin: 10px 0;
}
}
/* 超宽屏幕优化 */
@media screen and (min-width: 1200px) {
.container {
max-width: 1200px;
margin: 0 auto;
}
}
</style>
</head>
<body>
<div class="container">
<!-- 加密部分 -->
<div class="section">
<h3>加密内容</h3>
<div>
<textarea id="content-to-encrypt" placeholder="输入要加密的内容"></textarea>
</div>
<div>
<input type="password" id="encrypt-password" placeholder="设置加密密码">
<button onclick="encryptContent()">加密</button>
</div>
<div class="result" id="encrypted-result"></div>
</div>
<!-- 解密部分 -->
<div class="section">
<h3>解密内容</h3>
<div>
<textarea id="content-to-decrypt" placeholder="输入加密后的内容"></textarea>
</div>
<div>
<input type="password" id="decrypt-password" placeholder="输入解密密码">
<button onclick="decryptContent()">解密</button>
</div>
<div id="decrypt-error" class="error"></div>
<div class="result" id="decrypted-result"></div>
</div>
</div>
<script>
function encryptContent() {
const content = document.getElementById('content-to-encrypt').value;
const password = document.getElementById('encrypt-password').value;
if (!content || !password) {
alert('请输入内容和密码');
return;
}
try {
const encrypted = CryptoJS.AES.encrypt(content, password).toString();
document.getElementById('encrypted-result').textContent = encrypted;
document.getElementById('content-to-decrypt').value = encrypted;
} catch (e) {
alert('加密失败:' + e.message);
}
}
function decryptContent() {
const encryptedText = document.getElementById('content-to-decrypt').value;
const password = document.getElementById('decrypt-password').value;
const errorDiv = document.getElementById('decrypt-error');
const resultDiv = document.getElementById('decrypted-result');
if (!encryptedText || !password) {
errorDiv.textContent = '请输入加密内容和密码';
return;
}
try {
const decrypted = CryptoJS.AES.decrypt(encryptedText, password).toString(CryptoJS.enc.Utf8);
if (decrypted) {
resultDiv.textContent = decrypted;
errorDiv.textContent = '';
} else {
errorDiv.textContent = '解密失败:密码错误或内容格式不正确';
resultDiv.textContent = '';
}
} catch (e) {
errorDiv.textContent = '解密失败:' + e.message;
resultDiv.textContent = '';
}
}
document.getElementById('decrypt-password').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
decryptContent();
}
});
</script>
</body>
</html>
效果如下:
加密内容
解密内容
然后把加密后的密文放入前端中(替换位置在163行,支持markdown渲染):
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加密文章访问</title>
<!-- 使用 ES6 模块方式加载 marked -->
<script type="module">
import { marked } from 'https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js';
window.marked = marked;
marked.setOptions({
breaks: true,
gfm: true
});
</script>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
margin: 0;
padding: 0;
line-height: 1.6;
min-height: 100vh;
display: flex;
justify-content: center;
}
.container {
width: 100%;
max-width: 100%;
padding: clamp(15px, 3vw, 30px);
margin: 0 auto;
background: inherit;
}
.password-section {
max-width: 600px;
margin: 20px auto;
padding: 20px;
text-align: center;
background: inherit;
}
input[type="password"] {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
width: 200px;
margin-right: 10px;
background: inherit;
}
button {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
filter: brightness(90%);
}
.error-message {
color: #dc3545;
margin-top: 10px;
display: none;
}
.article-content {
width: 100%;
max-width: 100%;
padding: 0 max(20px, 5vw);
box-sizing: border-box;
opacity: 0;
display: none;
}
.article-content.visible {
opacity: 1;
display: block;
transition: opacity 0.5s ease;
}
.markdown-content {
width: 100%;
max-width: 100%;
margin: 0 auto;
line-height: 1.8;
}
@media screen and (max-width: 768px) {
.container {
padding: 10px;
}
input[type="password"], button {
width: 100%;
max-width: 300px;
margin: 10px 0;
}
}
</style>
</head>
<body>
<div class="container">
<div id="passwordSection" class="password-section">
<input type="password" id="passwordInput" placeholder="请输入密码">
<button onclick="verifyPassword()">验证密码</button>
<div id="errorMessage" class="error-message"></div>
</div>
<div id="articleContent" class="article-content">
<div id="articleBody" class="markdown-content"></div>
</div>
</div>
<script>
function showError(message) {
const errorElement = document.getElementById('errorMessage');
errorElement.textContent = message;
errorElement.style.display = 'block';
setTimeout(() => {
errorElement.style.display = 'none';
}, 3000);
if (message.includes('密码错误')) {
const passwordInput = document.getElementById('passwordInput');
passwordInput.value = '';
passwordInput.focus();
}
}
function showArticle(content) {
const passwordSection = document.getElementById('passwordSection');
passwordSection.style.display = 'none';
try {
const articleBody = document.getElementById('articleBody');
if (typeof window.marked === 'undefined') {
articleBody.textContent = content;
} else {
articleBody.innerHTML = window.marked.parse(content);
}
} catch (error) {
console.error('Markdown 渲染错误:', error);
document.getElementById('articleBody').textContent = content;
}
const articleContent = document.getElementById('articleContent');
articleContent.style.display = 'block';
setTimeout(() => {
articleContent.classList.add('visible');
}, 10);
}
function verifyPassword() {
const password = document.getElementById('passwordInput').value;
// 这里替换为你的加密内容和验证逻辑
const encryptedContent = "你的加密内容";
try {
const decrypted = CryptoJS.AES.decrypt(encryptedContent, password).toString(CryptoJS.enc.Utf8);
if (decrypted) {
showArticle(decrypted);
} else {
showError('密码错误,请重试');
}
} catch (e) {
showError('密码错误,请重试');
}
}
document.getElementById('passwordInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
verifyPassword();
}
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
</body>
</html>
效果演示(密码2025):
评论区