完成权限的验证

This commit is contained in:
HelloWorld 2020-03-25 10:39:53 +08:00
parent f7d99047d4
commit 78b7dd36c2
14 changed files with 215 additions and 8955 deletions

1
.gitignore vendored
View File

@ -35,3 +35,4 @@ app/
config.development.js config.development.js
adapter.development.js adapter.development.js
package-lock.json

8846
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,14 +11,15 @@
}, },
"dependencies": { "dependencies": {
"think-cache": "^1.0.0", "think-cache": "^1.0.0",
"think-session": "^1.0.0",
"think-cache-file": "^1.0.8", "think-cache-file": "^1.0.8",
"think-logger3": "^1.0.0",
"think-model": "^1.0.0", "think-model": "^1.0.0",
"think-model-mysql": "^1.0.0",
"think-session": "^1.0.0",
"think-session-file": "^1.0.5", "think-session-file": "^1.0.5",
"think-session-jwt": "^1.1.1",
"think-view": "^1.0.0", "think-view": "^1.0.0",
"think-view-nunjucks": "^1.0.1", "think-view-nunjucks": "^1.0.1",
"think-model-mysql": "^1.0.0",
"think-logger3": "^1.0.0",
"thinkjs": "^3.0.0" "thinkjs": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {

88
schema.sql Normal file
View File

@ -0,0 +1,88 @@
-- 用户信息表
drop table if exists users;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- id
`username` varchar(255) NOT NULL, -- 用户名
`password` varchar(255) NOT NULL, -- 密码
`email` varchar(255) NOT NULL, -- 邮箱
`created_at` datetime DEFAULT now(), -- 创建时间
`last_login` datetime DEFAULT NULL, -- 最后一次登录时间
`search_history` varchar(512) DEFAULT NULL, -- 历史搜索记录
`avatar` varchar(512) DEFAULT NULL, -- 头像地址
`quick_url` varchar(2048) DEFAULT '{\"B\":\"https://www.baidu.com/\",\"G\":\"https://www.google.com.hk/\",\"V\":\"https://www.v2ex.com/\",\"L\":\"http://luchenqun.com/\",\"H\":\"https://github.com/\",\"Q\":\"http://www.iqiyi.com/\",\"J\":\"https://www.jd.com/\"}', -- 全局快捷地址
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`)
);
-- 书签表
drop table if exists bookmarks;
CREATE TABLE `bookmarks` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- id
`user_id` int(11) NOT NULL, -- 用户id
`tag_id` int(11) NOT NULL, -- 分类id (只允许一个书签对应一个分类)
`title` varchar(255) NOT NULL, -- 标题
`description` varchar(4096) DEFAULT NULL, -- 描述
`url` varchar(1024) NOT NULL, -- 链接
`public` tinyint(4) DEFAULT '0', -- 是否公开 1 公开0 不公开
`click_count` smallint DEFAULT 1, -- 总共点击次数
`created_at` datetime DEFAULT now(), -- 创建时间
`last_click` datetime DEFAULT now(), -- 最后一次点击时间
PRIMARY KEY (`id`),
KEY `userIdIdx` (`user_id`)
);
-- 书签分类表
drop table if exists tags;
CREATE TABLE `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- id
`user_id` int(11) NOT NULL, -- 用户id
`name` varchar(32) NOT NULL, -- 标签
`last_use` datetime DEFAULT now(), -- 最后使用标签的时间
`sort` tinyint(8) DEFAULT 0, -- 书签排序
`show` tinyint(8) DEFAULT 1, -- 书签是否显示
PRIMARY KEY (`id`),
KEY `userIdIdx` (`user_id`)
);
-- 建议留言
drop table if exists advices;
CREATE TABLE `advices` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- id
`user_id` int(11) NOT NULL, -- 用户id
`comment` text NOT NULL, -- 评论
`created_at` datetime DEFAULT now(), -- 创建时间
`state` tinyint(4) DEFAULT '0', -- 处理结果
PRIMARY KEY (`id`),
KEY `userIdIdx` (`user_id`)
);
-- 书签表
drop table if exists hot_bookmarks;
CREATE TABLE `hot_bookmarks` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- id(articleId)
`date` int(11) NOT NULL DEFAULT 0, -- 日期(自己添加)
`title` varchar(255) DEFAULT NULL, -- 标题(title)
`description` varchar(4096) DEFAULT NULL, -- 描述(自己添加)
`url` varchar(1024) DEFAULT NULL, -- 链接(url)
`fav_count` smallint DEFAULT 1, -- 总共收藏人数(favCount)
`created_by` varchar(64) DEFAULT NULL, -- 创建者(sourceName)
`created_at` bigint DEFAULT 0, -- 创建时间(updatetime)
`last_click` bigint DEFAULT 0, -- 最后一次点击时间(createtime)
`snap_url` varchar(1024) DEFAULT NULL, -- 截图链接(imageList[0])
`favicon_url` varchar(1024) DEFAULT NULL, -- icon链接(sourceLogo)
`status` tinyint(4) DEFAULT '0', -- 状态
PRIMARY KEY (`id`)
);
-- 备忘录
drop table if exists notes;
CREATE TABLE `notes` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- id
`user_id` int(11) NOT NULL, -- 用户id
`content` text NOT NULL, -- 备忘内容
`tag_id` int(11) NOT NULL, -- 分类id
`created_at` datetime DEFAULT now(), -- 创建时间
`public` tinyint(4) DEFAULT '0', -- 是否公开 1 公开0 不公开
PRIMARY KEY (`id`)
);

View File

@ -1,6 +1,6 @@
const fileCache = require('think-cache-file'); const fileCache = require('think-cache-file');
const nunjucks = require('think-view-nunjucks'); const nunjucks = require('think-view-nunjucks');
const fileSession = require('think-session-file'); const JWTSession = require('think-session-jwt');
const mysql = require('think-model-mysql'); const mysql = require('think-model-mysql');
const {Console, File, DateFile} = require('think-logger3'); const {Console, File, DateFile} = require('think-logger3');
const path = require('path'); const path = require('path');
@ -52,19 +52,27 @@ exports.model = {
* @type {Object} * @type {Object}
*/ */
exports.session = { exports.session = {
type: 'file', type: 'jwt',
common: { common: {
cookie: { cookie: {
name: 'mybookmark' name: 'thinkjs',
// keys: ['werwer', 'werwer'],
// signed: true
} }
}, },
file: { jwt: {
handle: fileSession, handle: JWTSession,
sessionPath: path.join(think.ROOT_PATH, 'runtime/session') secret: 'secret', // secret is reqired
tokenType: 'header', // ['query', 'body', 'header', 'cookie'], 'cookie' is default
tokenName: 'authorization', // if tokenType not 'cookie', this will be token name, 'jwt' is default 后端字母要小写
sign: {
// sign options is not required
expiresIn: '604800s' // 7天过期
},
verify: {
// verify options is not required
},
verifyCallback: (error) => { throw new Error("token verify error"); }, // default verify fail callback
}
} }
};
/** /**
* view adapter config * view adapter config

View File

@ -1,4 +1,6 @@
// default config // default config
module.exports = { module.exports = {
workers: 1 workers: 1,
errnoField: 'code',
errmsgField: 'msg'
}; };

View File

@ -7,17 +7,19 @@ function md5(str) {
module.exports = class extends Base { module.exports = class extends Base {
async __before() { async __before() {
let user = await this.session('user');
user = {}
console.log("session user", user);
if (['register', 'login'].indexOf(this.ctx.action) >= 0) { if (['register', 'login'].indexOf(this.ctx.action) >= 0) {
return; return;
} }
try {
// 获取用户的 session 信息,如果为空,返回 false 阻止后续的行为继续执行 let user = await this.session('user');
console.log(".......session user", this.ctx.action, Object.keys(user));
if (think.isEmpty(user)) { if (think.isEmpty(user)) {
return this.fail('NOT_LOGIN'); return this.fail(401, '请先登录');
}
this.ctx.state.user = user;
} catch (error) {
// 获取用户的 session 信息,如果为空,返回 false 阻止后续的行为继续执行
return this.fail(401, '请先登录:' + error.toString());
} }
} }
@ -48,20 +50,40 @@ module.exports = class extends Base {
if (think.isEmpty(data)) { if (think.isEmpty(data)) {
this.json({ code: 2, msg: "账号或者密码错误" }); this.json({ code: 2, msg: "账号或者密码错误" });
} else { } else {
delete data.password;
const token = await this.session('user', {
id: data.id,
username: data.username
});
data.token = token;
this.json({ code: 0, data, msg: "登陆成功" }); this.json({ code: 0, data, msg: "登陆成功" });
data.password = "******";
await this.session('user', data); // @todo 对session的maxAge进行操作(目前默认永久不过期)
} }
} catch (error) { } catch (error) {
this.json({ code: 1, data: '', msg: error.toString() }); this.json({ code: 1, data: '', msg: error.toString() });
} }
} }
async userInfoAction() { // 通过session获取自己信息
this.json({ code: 1, data: '', msg: '' }); async ownAction() {
let full = this.post().full;
if (full) {
let data = await this.model('users').where({ id: this.ctx.state.user.id }).find();
delete data.password;
this.json({ code: 0, data, msg: '' });
} else {
this.json({ code: 0, data: this.ctx.state.user, msg: '' });
}
} }
autoLoginAction() { async tagsAction() {
this.json({ "succ": true }); let tags = await this.model('tags').where({ user_id: this.ctx.state.user.id }).order('sort ASC, last_use DESC').select();
for (let tag of tags) {
let cnt = await this.model('tags_bookmarks').where({ tag_id: tag.id }).count();
let ncnt = await this.model('notes').where({ tag_id: tag.id }).count();
tag.cnt = cnt;
tag.ncnt = ncnt;
}
this.json({ code: 0, data: tags, msg: '' });
} }
}; };

View File

@ -1,17 +1,26 @@
var app = angular.module('bookmarkApp', ['ui.router', 'ngCookies', 'infinite-scroll', 'angular-sortable-view', 'ngDialog']); var app = angular.module('bookmarkApp', ['ui.router', 'ngCookies', 'infinite-scroll', 'angular-sortable-view', 'ngDialog']);
axios.defaults.baseURL = '/api/'; axios.defaults.baseURL = '/api/';
axios.defaults.headers.common['Authorization'] = localStorage.getItem("authorization");
// 添加响应拦截器 // 添加响应拦截器
axios.interceptors.response.use(function (response) { axios.interceptors.response.use(function (response) {
let data = response.data; let reply = response.data;
if (data.code === 0) { if (reply.code === 0) {
if (data.msg) { if (reply.msg) {
toastr.success(data.msg, "提示"); toastr.success(reply.msg, "提示");
} }
return Promise.resolve(data.data); return Promise.resolve(reply.data);
} else { } else {
toastr.error(`错误信息:${data.msg}(错误码:${data.code})`, '请求错误'); toastr.error(`错误信息:${reply.msg}(错误码:${reply.code})`, '请求错误');
return Promise.reject(data); if (reply.code == 401) {
let hash = document.location.hash;
let origin = document.location.origin;
if (!(hash == "#/login" || hash == "#/")) {
window.location.href = `${origin}/#/login`;
}
}
return Promise.reject(reply);
} }
}, function (error) { }, function (error) {
toastr.error(`错误信息:${error.toString()}`, '网络错误'); toastr.error(`错误信息:${error.toString()}`, '网络错误');

View File

@ -11,13 +11,7 @@ app.controller('adviceCtr', ['$scope', '$state', '$timeout', 'bookmarkService',
$scope.category = ["功能", "BUG", "其他"]; $scope.category = ["功能", "BUG", "其他"];
$scope.user = {}; $scope.user = {};
bookmarkService.userInfo({}) axios.get('own', {}).then(user => $scope.user = user);
.then((data) => {
$scope.user = data;
})
.catch((err) => {
});
$scope.ok = function () { $scope.ok = function () {
if ($scope.comment == '') { if ($scope.comment == '') {

View File

@ -272,7 +272,7 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
}) })
}); });
function getBookmarks() { async function getBookmarks() {
var params = {} var params = {}
params.showStyle = $scope.showStyle params.showStyle = $scope.showStyle
params.currentPage = $scope.currentPage; params.currentPage = $scope.currentPage;

View File

@ -4,35 +4,18 @@ app.controller('homeCtr', ['$scope', '$stateParams', '$filter', '$state', '$wind
$window.location = "http://m.mybookmark.cn/#/tags"; $window.location = "http://m.mybookmark.cn/#/tags";
return; return;
} }
bookmarkService.autoLogin()
.then((data) => { (async () => {
if (data.logined) { try {
pubSubService.publish('loginCtr.login', { await axios.get('own', {});
'login': data.logined, pubSubService.publish('loginCtr.login', { 'login': true });
});
$state.go('tags'); $state.go('tags');
toastr.success('自动登陆成功,系统将自动跳转到书签分类页面', "提示"); } catch (error) {
} else {
console.log('autoLogin failed......................')
pubSubService.publish('Common.menuActive', { pubSubService.publish('Common.menuActive', {
login: false, login: false,
index: dataService.NotLoginIndexHome index: dataService.NotLoginIndexHome
}); });
transition();
} }
}) })();
.catch((err) => {
console.log('autoLogin err', err);
transition();
});
$('.js-segment-home').transition('hide');
function transition() {
var className = 'js-segment-home';
$('.' + className).transition('hide');
$('.' + className).transition({
animation: dataService.animation(),
duration: 500,
});
}
}]); }]);

View File

@ -38,10 +38,12 @@ app.controller('loginCtr', ['$scope', '$filter', '$state', '$http', '$cookieStor
}; };
$cookieStore.put("username", $scope.username); $cookieStore.put("username", $scope.username);
await axios.post('login', params); let data = await axios.post('login', params);
return; axios.defaults.headers.common['Authorization'] = data.token;
localStorage.setItem("authorization", data.token);
pubSubService.publish('loginCtr.login', { login: true }); pubSubService.publish('loginCtr.login', { login: true });
$state.go('bookmarks', {}) $state.go('tags')
} }
$scope.showRegister = async function () { $scope.showRegister = async function () {

View File

@ -26,16 +26,12 @@ app.controller('menuCtr', ['$scope', '$stateParams', '$state', '$window', '$time
$scope.loginMenus = dataService.loginMenus; // 登陆之后显示的菜单数据。uiSerf内部跳转链接。 $scope.loginMenus = dataService.loginMenus; // 登陆之后显示的菜单数据。uiSerf内部跳转链接。
$scope.notLoginMenus = dataService.notLoginMenus; // 未登陆显示的菜单数据 $scope.notLoginMenus = dataService.notLoginMenus; // 未登陆显示的菜单数据
bookmarkService.userInfo({}) (async () => {
.then((data) => { $scope.user = await axios.get('own', {});
$scope.user = data;
if (data.username === 'lcq') { if (data.username === 'lcq') {
$scope.loginMenus[dataService.LoginIndexHot].show = false; $scope.loginMenus[dataService.LoginIndexHot].show = false;
} }
}) })();
.catch((err) => {
});
$scope.toggleReady = function (ready) { $scope.toggleReady = function (ready) {
if (ready) { if (ready) {
@ -248,10 +244,8 @@ app.controller('menuCtr', ['$scope', '$stateParams', '$state', '$window', '$time
}); });
} }
(async () => {
let user = await axios.get('own', { full: true });
bookmarkService.userInfo({})
.then((user) => {
$scope.searchHistory = JSON.parse(user.search_history || '[]'); $scope.searchHistory = JSON.parse(user.search_history || '[]');
$scope.quickUrl = JSON.parse(user.quick_url || '{}'); $scope.quickUrl = JSON.parse(user.quick_url || '{}');
$scope.searchHistory.forEach((item, index) => { $scope.searchHistory.forEach((item, index) => {
@ -266,11 +260,7 @@ app.controller('menuCtr', ['$scope', '$stateParams', '$state', '$window', '$time
$('.js-field-' + showStyle).addClass('active selected'); $('.js-field-' + showStyle).addClass('active selected');
} }
}, 1000) }, 1000)
}) })();
.catch((err) => {
console.log(err);
// toastr.error('获取信息失败。错误信息:' + JSON.stringify(err), "错误");
});
$timeout(function () { $timeout(function () {
$('.suggest') $('.suggest')

View File

@ -5,7 +5,11 @@ app.controller('tagsCtr', ['$scope', '$filter', '$state', '$window', '$statePara
return; return;
} }
getTags({}); (async () => {
await getTags();
})()
// getTags({});
var perPageItems = 20; var perPageItems = 20;
var dialog = null; var dialog = null;
@ -486,8 +490,10 @@ app.controller('tagsCtr', ['$scope', '$filter', '$state', '$window', '$statePara
}) })
}); });
function getTags(params) { async function getTags(params) {
$scope.loadTags = true; $scope.loadTags = true;
$scope.tags = await axios.get('tags');
return;
bookmarkService.getTags(params) bookmarkService.getTags(params)
.then((data) => { .then((data) => {
$scope.tags = [] $scope.tags = []