用户-角色-权限
的授权模型字段 | 字段名 | 类型 | 默认 |
---|---|---|---|
id | ID | int(11) | |
userName | 用户名 | varchar(255) | |
password | 密码 | varchar(255) |
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(255),
`password` varchar(255),
PRIMARY KEY (`id`)
)
INSERT INTO `user` VALUES (1, 'isadmin', '123456');
INSERT INTO `user` VALUES (2, 'isuser', '123456');
字段 | 字段名 | 类型 | 默认 |
---|---|---|---|
id | ID | int(11) | |
name | 名称 | varchar(255) | |
desc | 描述 | varchar(255) |
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) ,
`desc` varchar(255) ,
PRIMARY KEY (`id`)
) E
INSERT INTO `role` VALUES (1, 'admin', '管理员');
INSERT INTO `role` VALUES (2, 'user', '普通用户');
字段 | 字段名 | 类型 | 默认 |
---|---|---|---|
id | ID | int(11) | |
name | 名称 | varchar(255) | |
parent_id | 父ID | int(11) | |
icon | 图标 | varchar(255) | |
key | 路径 | varchar(255) | |
type | 类型 | varchar(32) |
CREATE TABLE `permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) ,
`parent_id` int(11) NULL DEFAULT NULL,
`icon` varchar(255) ,
`key` varchar(255) ,
`type` varchar(255) ,
PRIMARY KEY (`id`)
);
INSERT INTO `permission` VALUES (1, '授权平台', 0, 'desktop', '/api', 'menu');
INSERT INTO `permission` VALUES (2, '角色管理', 1, 'team', '/api/role', 'menu');
INSERT INTO `permission` VALUES (3, '用户管理', 1, 'user', '/api/user', 'menu');
INSERT INTO `permission` VALUES (4, '权限管理', 1, 'idcard', '/api/resource', 'menu');
INSERT INTO `permission` VALUES (5, '添加用户', 3, 'team', '/api/user/add', 'button');
INSERT INTO `permission` VALUES (6, '删除用户', 3, 'team', '/api/user/delete', 'button');
字段 | 字段名 | 类型 |
---|---|---|
role_id | 角色ID | int(11) |
user_id | 用户ID | int(11) |
DROP TABLE IF EXISTS `role_user`;
CREATE TABLE `role_user` (
`role_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`, `role_id`)
)
INSERT INTO `role_user` VALUES (1, 1);
INSERT INTO `role_user` VALUES (2, 2);
字段 | 字段名 | 类型 |
---|---|---|
role_id | 角色ID | int(11) |
permission_id | 资源ID | int(11) |
CREATE TABLE `role_permission` (
`role_id` int(11) NOT NULL,
`permission_id` int(255) NOT NULL,
PRIMARY KEY (`role_id`, `permission_id`)
)
INSERT INTO `role_permission` VALUES (1, 1);
INSERT INTO `role_permission` VALUES (1, 2);
INSERT INTO `role_permission` VALUES (1, 3);
INSERT INTO `role_permission` VALUES (1, 4);
INSERT INTO `role_permission` VALUES (1, 5);
INSERT INTO `role_permission` VALUES (1, 6);
INSERT INTO `role_permission` VALUES (2, 1);
INSERT INTO `role_permission` VALUES (2, 4);
mkdir client-side
cd client-side
cnpm init egg --type=ts
cnpm i
cnpm run dev
cnpm i --save egg-mysql
import { EggPlugin } from 'egg';
const plugin: EggPlugin = {
+ mysql: {
+ enable: true,
+ package: 'egg-mysql'
+ }
};
export default plugin;
config\config.default.ts
import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg';
export default (appInfo: EggAppInfo) => {
const config = {} as PowerPartial<EggAppConfig>;
// override config from framework / plugin
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1580620890875_8931';
// add your egg config in here
config.middleware = [];
+ config.mysql = {
+ // 单数据库信息配置
+ client: {
+ // host
+ host: 'localhost',
+ // 端口号
+ port: '3306',
+ // 用户名
+ user: 'root',
+ // 密码
+ password: 'root',
+ // 数据库名
+ database: 'cms'
+ },
+ // 是否加载到 app 上,默认开启
+ app: true,
+ // 是否加载到 agent 上,默认关闭
+ agent: false,
+ };
// add your special config in here
const bizConfig = {
sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`,
};
// the return config will combines to EggAppConfig
return {
...config,
...bizConfig,
};
};
import 'egg';
declare module 'egg' {
+ interface Application {
+ mysql: any;
+ }
}
import { Controller } from 'egg';
export default class HomeController extends Controller {
public async index() {
const { ctx } = this;
+ let users = await this.app.mysql.select('user');
+ ctx.body = {
+ success: true,
+ data: users
+ };
//ctx.body = await ctx.service.test.sayHi('egg');
}
}
cnpm i --save egg-passport passport-local
config\plugin.ts
import { EggPlugin } from 'egg';
const plugin: EggPlugin = {
mysql: {
enable: true,
package: 'egg-mysql'
},
+ passport: {
+ enable: true,
+ package: 'egg-passport'
+ },
+ passportLocal: {
+ enable: true,
+ package: 'egg-passport-local'
+ }
};
export default plugin;
typings\index.d.ts
import 'egg';
declare module 'egg' {
interface Application {
mysql: any;
+ passport: any;
}
}
app.ts
import { Application, IBoot } from 'egg';
import { Strategy } from 'passport-local';
export default class FooBoot implements IBoot {
private readonly app: Application;
constructor(app: Application) {
this.app = app;
}
configDidLoad() {
//Config, plugin files have loaded.
let { app } = this;
app.passport.use(new Strategy({ usernameField: 'userName', passReqToCallback: true }, async (req, userName, password, done) => {
const users = await this.app.mysql.select('user', { where: { userName, password }, limit: 1, offset: 0, });
if (users && users.length > 0) {
let user = users[0];
let roles = await this.app.mysql.query(`SELECT role.* FROM user INNER JOIN role_user ON user.id = role_user.user_id inner JOIN role ON role_user.role_id=role.id WHERE user.id=?`, [user.id]);
user.currentAuthority = roles.map(role => role.name);
return done(null, user);
} else {
req.ctx.isAuthenticated() && req.ctx.logout();
return done(null, false);
}
}));
}
}
app\controller\user.ts
import { Controller } from 'egg';
export default class userController extends Controller {
public async loginCallback() {
let { ctx } = this;
if (ctx.isAuthenticated()) {
ctx.body = {
status: 'ok',
type: ctx.user.type,
currentAuthority: ctx.user.currentAuthority
}
} else {
ctx.body = {
success: false,
error: '用户名或密码错误'
}
}
}
public async addUser2() {
let { ctx } = this;
if (ctx.isAuthenticated()) {
let user = ctx.user;
let url = ctx.url;
let permissions = await this.app.mysql.query(`SELECT permission.key FROM user INNER JOIN role_user ON user.id = role_user.user_id inner JOIN role_permission ON role_user.role_id=role_permission.role_id INNER JOIN permission ON role_permission.permission_id = permission.id WHERE user.id=?`, [user.id]);
let allowed = permissions.map(item => item.key).includes(url);
if (allowed) {
ctx.body = {
success: true,
error: '添加用户成功'
}
} else {
ctx.body = {
success: false,
error: '用户未授权'
}
}
} else {
ctx.body = {
success: false,
error: '用户未授权'
}
}
}
public async addUser() {
let { ctx } = this;
ctx.body = {
success: true,
error: '添加用户成功'
}
}
}
app\middleware\auth.ts
module.exports = (_options, _app) => {
return async function (ctx, next) {
if (ctx.isAuthenticated()) {
let user = ctx.user;
let url = ctx.url;
let permissions = await ctx.app.mysql.query(`SELECT permission.key FROM user INNER JOIN role_user ON user.id = role_user.user_id inner JOIN role_permission ON role_user.role_id=role_permission.role_id INNER JOIN permission ON role_permission.permission_id = permission.id WHERE user.id=?`, [user.id]);
let allowed = permissions.map(item => item.key).includes(url);
if (allowed) {
await next();
} else {
ctx.body = { success: false, error: '用户未授权' };
}
} else {
ctx.body = { success: false, error: '用户未授权' };
}
}
}
app\router.ts
import { Application } from 'egg';
export default (app: Application) => {
const { controller, router } = app;
router.get('/', controller.home.index);
+ const localStrategy = app.passport.authenticate('local', { successRedirect: '/server/api/loginCallback', failureRedirect: '/server/api/loginCallback' });
+ router.post('/api/login/account', localStrategy);
+ const auth = app.middleware.auth();
+ router.post('/api/user/add', auth, controller.user.addUser);
+ router.get('/api/loginCallback', controller.user.loginCallback);
};
+ config.security = {
+ csrf: false
+ }
ctrl+shift+p
Debug: Toggle Auto Attach
umi -v
umi ui
config\config.ts
+ proxy: {
+ '/server/api/': {
+ target: 'http://localhost:7001/',
+ changeOrigin: true,
+ pathRewrite: { '^/server': '' },
+ },
+ },
config\config.ts
routes: [
{
path: '/user',
component: '../layouts/UserLayout',
routes: [
{
name: 'login',
path: '/user/login',
component: './user/login',
},
],
},
{
path: '/',
component: '../layouts/SecurityLayout',
routes: [
{
path: '/',
component: '../layouts/BasicLayout',
authority: ['admin', 'user'],
routes: [
{
path: '/',
redirect: '/welcome',
},
{
path: '/welcome',
name: 'welcome',
icon: 'smile',
component: './Welcome',
},
{
path: '/admin',
name: '权限平台',
icon: 'crown',
//component: './Admin',
//authority: ['admin'],
routes: [
{
name: '角色管理',
icon: 'smile',
path: '/admin/role',
component: './admin/Role',
authority: ['admin']
},
{
name: '用户管理',
icon: 'smile',
path: '/admin/user',
component: './admin/User',
authority: ['admin', 'user']
},
{
name: '权限管理',
icon: 'smile',
path: '/admin/permission',
component: './admin/Permission',
authority: ['admin']
},
],
},
{
component: './404',
},
],
},
{
component: './404',
},
],
},
{
component: './404',
},
],
src\pages\admin\User\index.tsx
+import { queryRule, updateRule, addUser, removeRule } from './service';
+import Authorized from '@/utils/Authorized';
+<Authorized authority={['admin', 'user']} noMatch={null}>
+ <Button icon={'plus'} type="primary" onClick={() => handleModalVisible(true)}>
+ 新建
+ </Button>
+</Authorized>