
рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЖрдзреБрдирд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ, рд╣рдо рдЕрдХреНрд╕рд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЬреЛ рдЙрд╕рдХреА рднреВрдорд┐рдХрд╛ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдЕрддрд┐рдерд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдПрдХ рд▓реЗрдЦ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдПрдХ рдкрдВрдЬреАрдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдпрд╛ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрдЯрди рджреЗрдЦрддрд╛ рд╣реИред
рдЗрд╕ рджреГрд╢реНрдпрддрд╛ рдХреЛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдирд╛ рдмрдврд╝рддреА рднреВрдорд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдкреВрд░реНрдг рджреБрдГрд╕реНрд╡рдкреНрди рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЖрдкрдиреЗ рд╢рд╛рдпрдж рдЗрд╕ рддрд░рд╣ рдХреЛрдб рд▓рд┐рдЦрд╛ рдпрд╛ рджреЗрдЦрд╛ рд╣реИ:
if (user.role === ADMIN || user.auth && post.author === user.id) { res.send(post) } else { res.status(403).send({ message: 'You are not allowed to do this!' }) }
рдЗрд╕ рддрд░рд╣ рдХреЗ рдХреЛрдб рдХреЛ рдкреВрд░реЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рд╡рд┐рддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЖрдорддреМрд░ рдкрд░ рдПрдХ рдмрдбрд╝реА рд╕рдорд╕реНрдпрд╛ рдмрди рдЬрд╛рддреА рд╣реИ рдЬрдм рдЧреНрд░рд╛рд╣рдХ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рдмрджрд▓рддрд╛ рд╣реИ рдпрд╛ рдЕрддрд┐рд░рд┐рдХреНрдд рднреВрдорд┐рдХрд╛рдПрдВ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реИред рдЕрдВрдд рдореЗрдВ, рдЖрдкрдХреЛ рдРрд╕реЗ рд╕рднреА if-s рд╕реЗ рдЧреБрдЬрд░рдиреЗ рдФрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдЪреЗрдХ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ CASL рдирд╛рдордХ рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Expressjs рдПрдкреАрдЖрдИ рдореЗрдВ рдЕрдиреБрдорддрд┐ рдкреНрд░рдмрдВрдзрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рддрд░реАрдХрд╛ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ ред рдпрд╣ рдПрдХреНрд╕реЗрд╕ рдХрдВрдЯреНрд░реЛрд▓ рдХреЛ рдмрд╣реБрдд рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЖрдкрдХреЛ рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ:
if (req.ability.can('read', post)) { res.send(post) } else { res.status(403).send({ message: 'You are not allowed to do this!' }) }
CASL рдХреЗ рд▓рд┐рдП рдирдпрд╛? рдореИрдВ рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ CASL рдХреНрдпрд╛ рд╣реИ?
рдиреЛрдЯ: рдпрд╣ рд▓реЗрдЦ рдореВрд▓ рд░реВрдк рд╕реЗ рдордзреНрдпрдо рдкрд░ рдкреНрд░рдХрд╛рд╢рд┐рдд рд╣реБрдЖ рдерд╛ ред
рдбреЗрдореЛ рдРрдк
рдПрдХ рдкрд░реАрдХреНрд╖рдг рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВрдиреЗ рдмреНрд▓реЙрдЧ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рд╕рд░рд▓ REST API рдмрдирд╛рдпрд╛ред рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ 3 рдЗрдХрд╛рдЗрдпрд╛рдВ ( User
, Post
рдФрд░ Comment
) рдФрд░ 4 рдореЙрдбреНрдпреВрд▓ (рдкреНрд░рддреНрдпреЗрдХ рдЗрдХрд╛рдИ рдХреЗ рд▓рд┐рдП рдПрдХ рдореЙрдбреНрдпреВрд▓ рдФрд░ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреНрдп) рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рд╕рднреА рдореЙрдбреНрдпреВрд▓ src/modules
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдкрд╛рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдорд╛рдирд╕ рдореЙрдбрд▓, рдкрд╛рд╕рдкреЛрд░реНрдЯ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдФрд░ CASL- рдЖрдзрд╛рд░рд┐рдд рдкреНрд░рд╛рдзрд┐рдХрд░рдг (рдпрд╛ рдЕрднрд┐рдЧрдо рдирд┐рдпрдВрддреНрд░рдг) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ:
- рд╕рднреА рд▓реЗрдЦ рдФрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ рдкрдврд╝реЗрдВ
- рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдмрдирд╛рдПрдВ (рдпрд╛рдиреА, рдкрдВрдЬреАрдХрд░рдг рдХрд░реЗрдВ)
- рдЕрдзрд┐рдХреГрдд рд╣реЛрдиреЗ рдкрд░ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд▓реЗрдЦ (рдмрдирд╛рдПрдВ, рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ, рд╣рдЯрд╛рдПрдВ) рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░реЗрдВ
- рдЕрдзрд┐рдХреГрдд рд╣реЛрдиреЗ рдкрд░ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЬрд╛рдирдХрд╛рд░реА рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ
- рдЕрдзрд┐рдХреГрдд рд╣реЛрдиреЗ рдкрд░ рдЕрдкрдиреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░реЗрдВ
рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕реЗ рдХреЗрд╡рд▓ npm install
рд╕реЗ рдХреНрд▓реЛрди рдХрд░реЗрдВ рдФрд░ npm install
рдФрд░ npm start
ред рдЖрдкрдХреЛ MongoDB рд╕рд░реНрд╡рд░ рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЖрд╡реЗрджрди mongodb://localhost:27017/blog
рдЬреЛрдбрд╝рддрд╛ рд╣реИ mongodb://localhost:27017/blog
ред рд╕рдм рдХреБрдЫ рддреИрдпрд╛рд░ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк рдереЛрдбрд╝рд╛ рдЦреЗрд▓ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЗрд╕реЗ рдФрд░ рдЕрдзрд┐рдХ рдордЬрд╝реЗрджрд╛рд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП db/
рдлрд╝реЛрд▓реНрдбрд░ рд╕реЗ рдореВрд▓ рдбреЗрдЯрд╛ рдЖрдпрд╛рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
mongorestore ./db
рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ, рдЖрдк README рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдлрд╝рд╛рдЗрд▓ рдХреЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдореЗрд░реЗ рдкреЛрд╕реНрдЯрдореИрди рд╕рдВрдЧреНрд░рд╣ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЪрд╛рд▓ рдХреНрдпрд╛ рд╣реИ?
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, CASL рдХрд╛ рдорд╣рд╛рди рд▓рд╛рдн рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдЖрдкрдХреЛ рд╕рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рдкрд╣реБрдБрдЪ рдЕрдзрд┐рдХрд╛рд░ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ! рджреВрд╕рд░реЗ, CASL рдЗрд╕ рдмрд╛рдд рдкрд░ рдХреЗрдВрджреНрд░рд┐рдд рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреМрди рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд╣ рдХреНрдпрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддреНред рдЕрдкрдиреА рдХреНрд╖рдорддрд╛рдУрдВ рдкрд░ред рдпрд╣ рдЖрдкрдХреЛ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХреНрд╖рдорддрд╛рдУрдВ рдХреЗ рдмрд┐рдирд╛ рд╡рд┐рднрд┐рдиреНрди рдХреНрд╖рдорддрд╛рдУрдВ рдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рдореВрд╣реЛрдВ рдХреЛ рдЗрди рдХреНрд╖рдорддрд╛рдУрдВ рдХреЛ рд╡рд┐рддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рдо рдЕрдзрд┐рдХреГрдд рдФрд░ рдЕрдирдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдкрд╣реБрдБрдЪ рдЕрдзрд┐рдХрд╛рд░ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
const { AbilityBuilder, Ability } = require('casl') function defineAbilitiesFor(user) { const { rules, can } = AbilityBuilder.extract() can('read', ['Post', 'Comment']) can('create', 'User') if (user) { can(['update', 'delete', 'create'], ['Post', 'Comment'], { author: user._id }) can(['read', 'update'], 'User', { _id: user._id }) } return new Ability(rules) } const ANONYMOUS_ABILITY = defineAbilitiesFor(null) module.exports = function createAbilities(req, res, next) { req.ability = req.user.email ? defineAbilitiesFor(req.user) : ANONYMOUS_ABILITY next() }
рдЕрдм рдКрдкрд░ рд▓рд┐рдЦреЗ рдХреЛрдб рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░реЗрдВред AbilityBuilder
-a рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг defineAbilitiesFor(user)
AbilityBuilder
рдореЗрдВ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЗрд╕рдХреА рдПрдХреНрд╕рдЯреНрд░реИрдХреНрдЯ рд╡рд┐рдзрд┐ рдЗрд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ 2 рд╕рд░рд▓ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд can
рдФрд░ rules
рдХрд╛ рдПрдХ рд╕рд░рдгреА рдФрд░ cannot
(рдЗрд╕ рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧ cannot
рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ)ред рдЕрдЧрд▓рд╛, рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп can
рд╣реИ, рд╣рдо рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреНрдпрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ: рдкрд╣рд▓рд╛ рддрд░реНрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ (рдпрд╛ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА) рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ, рджреВрд╕рд░рд╛ рддрд░реНрдХ рдЙрд╕ рд╡рд╕реНрддреБ рдХрд╛ рдкреНрд░рдХрд╛рд░ рд╣реИ рдЬрд┐рд╕ рдкрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ (рдпрд╛ рдкреНрд░рдХрд╛рд░ рдХреА рдПрдХ рд╕рд░рдгреА) рдХреА рдЬрд╛рддреА рд╣реИ, рдФрд░ рд╕реНрдерд┐рддрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рддреАрд╕рд░реЗ рд╡реИрдХрд▓реНрдкрд┐рдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╕реНрдерд┐рддрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рддрдм рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдХрдХреНрд╖рд╛ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рдПрдХреНрд╕реЗрд╕ рдЕрдзрд┐рдХрд╛рд░реЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ, рдЕрд░реНрдерд╛рддред рдпрд╣ рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ post
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА author
рд╕рдВрдкрддреНрддрд┐ рдФрд░ user._id
рд╕рдорд╛рди рд╣реИрдВ, рдпрджрд┐ рд╡реЗ рд╣реИрдВ, рддреЛ true
рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛, рдЕрдиреНрдпрдерд╛ false
ред рд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреВрдВрдЧрд╛:
// Post is a mongoose model const post = await Post.findOne() const user = await User.findOne() const ability = defineAbilitiesFor(user) console.log(ability.can('update', post)) // post.author === user._id, true
рдЕрдЧрд▓рд╛, if (user)
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП if (user)
рд╣рдо рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдЕрдзрд┐рдХрд╛рд░ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ (рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдзрд┐рдХреГрдд рдирд╣реАрдВ рд╣реИ, рддреЛ рд╣рдореЗрдВ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рд╡рд╣ рдХреМрди рд╣реИ рдФрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╡рд╕реНрддреБ рдирд╣реАрдВ рд╣реИ)ред рдЕрдВрдд рдореЗрдВ, рд╣рдо Ability
рдХреНрд▓рд╛рд╕ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреА рдорджрдж рд╕реЗ рд╣рдо рдПрдХреНрд╕реЗрд╕ рдЕрдзрд┐рдХрд╛рд░реЛрдВ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВрдЧреЗред
рдЕрдЧрд▓рд╛, рд╣рдо ANONYMOUS_ABILITY
рд╕реНрдерд┐рд░рд╛рдВрдХ рдмрдирд╛рддреЗ рд╣реИрдВ, рдпрд╣ рдЕрдирдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП Ability
рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред рдЕрдВрдд рдореЗрдВ, рд╣рдо рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдирд┐рд░реНрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП Ability
рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред
рдкрд░реАрдХреНрд╖рдг рдПрдкреАрдЖрдИ
рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдкреЛрд╕реНрдЯрдореИрди рдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рд╣реБрдЖред рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдкрд╣реБрдБрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ:
POST /session { "session": { "email": "casl@medium.com", "password": "password" } }
рдЖрдкрдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рдорд┐рд▓рддрд╛ рд╣реИ:
{ "accessToken": "...." }
рдЗрд╕ рдЯреЛрдХрди рдХреЛ Authorization header
рдореЗрдВ рдбрд╛рд▓рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдмрд╛рдж рдХреЗ рд╕рднреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд╕рд╛рде рднреЗрдЬрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЕрдм рд▓реЗрдЦ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред
PATCH http://localhost:3030/posts/597649a88679237e6f411ae6 { "post": { "title": "[UPDATED] my post title" } } 200 Ok { "post": { "_id": "597649a88679237e6f411ae6", "updatedAt": "2017-07-24T19:53:09.693Z", "createdAt": "2017-07-24T19:25:28.766Z", "title": "[UPDATED] my post title", "text": "very long and interesting text", "author": "597648b99d24c87e51aecec3", "__v": 0 } }
рд╕рдм рдХреБрдЫ рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдЕрдЧрд░ рд╣рдо рдХрд┐рд╕реА рдФрд░ рдХреЗ рд▓реЗрдЦ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ?
PATCH http://localhost:3030/posts/59761ba80203fb638e9bd85c { "post": { "title": "[EVIL ACTION] my post title" } } 403 { "status": "forbidden", "message": "Cannot execute \"update\" on \"Post\"" }
рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реЛ рдЧрдИ! рдЬреИрд╕реА рдЙрдореНрдореАрдж рдереА :)
рдЕрдм рдХрд▓реНрдкрдирд╛ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдмреНрд▓реЙрдЧ рдХреЗ рд▓реЗрдЦрдХреЛрдВ рдХреЗ рд▓рд┐рдП рд╣рдо рдПрдХ рдкреЗрдЬ рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдЬрд╣рд╛рдБ рд╡реЗ рд╕рднреА рдкреЛрд╕реНрдЯ рджреЗрдЦ рд╕рдХреЗрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╡реЗ рдЕрдкрдбреЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╡рд┐рд╢рд┐рд╖реНрдЯ рддрд░реНрдХ рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ, рдпрд╣ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИ, рдЖрдкрдХреЛ рдмрд╕ рдЙрди рд╕рднреА рд▓реЗрдЦреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрд┐рдирдореЗрдВ рд▓реЗрдЦрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИред рд▓реЗрдХрд┐рди рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА CASL рдХреА рдорджрдж рд╕реЗ рдЗрд╕ рддрд░рд╣ рдХреЗ рддрд░реНрдХ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд▓рд┐рдпрд╛ рд╣реИ, рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдиреБрд░реЛрдз рд▓рд┐рдЦреЗ рдмрд┐рдирд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдРрд╕реЗ рд╕рднреА рд▓реЗрдЦреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛, рдФрд░ рдпрджрд┐ рдЕрдзрд┐рдХрд╛рд░ рдмрджрд▓рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдЕрдиреБрд░реЛрдз рдХреЛ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ - рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рдо :)ред
рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, CASL рдХреЗ рдкрд╛рд╕ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд npm рдкреИрдХреЗрдЬ рд╣реИ - @ casl / mongoose ред рдпрд╣ рдкреИрдХреЗрдЬ рдЖрдкрдХреЛ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЕрдиреБрдорддрд┐ рдХреЗ рдЕрдиреБрд╕рд╛рд░ MongoDB рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рдХреНрд╡реЗрд░реА рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ! рдорд╛рдирдЧреЛ рдХреЗ рд▓рд┐рдП, рдпрд╣ рдкреИрдХреЗрдЬ рдПрдХ рдкреНрд▓рдЧрдЗрди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдореЙрдбрд▓ рдореЗрдВ accessibleBy(ability, action)
рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдЗрд╕ рдкрджреНрдзрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рдХрд╛ рдЕрдиреБрд░реЛрдз рднреА рдХрд░реЗрдВрдЧреЗ ( CASL рдкреНрд░рд▓реЗрдЦрди рдФрд░ README рдкреИрдХреЗрдЬ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдкрдврд╝реЗрдВ)ред
рдпрд╣ рдареАрдХ рдЙрд╕реА рддрд░рд╣ рд╣реИ рдЬреИрд╕реЗ /posts
рд▓рд┐рдП handler
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ /posts
рд╣реИ (рдореИрдВрдиреЗ рдпрд╣ рднреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝реА рдХрд┐ рдЖрдкрдХреЛ рдХрд┐рди рдЕрдиреБрдорддрд┐рдпреЛрдВ рдХреА рдЬрд╛рдБрдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ):
Post.accessibleBy(req.ability, req.query.action)
рдЗрд╕рд▓рд┐рдП, рдкрд╣рд▓реЗ рдмрддрд╛рдИ рдЧрдИ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдкреИрд░рд╛рдореАрдЯрд░ action=update
рдЬреЛрдбрд╝реЗрдВ:
GET http://localhost:3030/posts?action=update 200 Ok { "posts": [ { "_id": "597649a88679237e6f411ae6", "updatedAt": "2017-07-24T19:53:09.693Z", "createdAt": "2017-07-24T19:25:28.766Z", "title": "[UPDATED] my post title", "text": "very long and interesting text", "author": "597648b99d24c87e51aecec3", "__v": 0 } ] }
рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ
CASL рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХреНрд╕реЗрд╕ рдЕрдзрд┐рдХрд╛рд░реЛрдВ рдХреЛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рд╣реИ рдХрд┐ рдкреНрд░рдХрд╛рд░ рдХреЗ рдирд┐рд░реНрдорд╛рдг рд╕реЗ рдЕрдзрд┐рдХ рд╣реИ
if (ability.can('read', post)) ...
рдЬреНрдпрд╛рджрд╛ рд╕рд╛рдл рдФрд░ рдЖрд╕рд╛рди
if (user.role === ADMIN || user.auth && todo.author === user.id) ...
CASL рдХреЗ рд╕рд╛рде, рд╣рдо рд╕реНрдкрд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░рд╛ рдХреЛрдб рдХреНрдпрд╛ рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрд╕ рддрд░рд╣ рдХреЗ рдЪреЗрдХ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ рдХрд╣реАрдВ рдФрд░ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗ, рдФрд░ рдпрд╣ рдпрд╣рд╛рдВ рд╣реИ рдХрд┐ CASL рдХреЛрдб рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдмрдЪрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ред
рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЖрдк CASL рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрдврд╝рдиреЗ рдореЗрдВ рдЙрддрдиреЗ рд╣реА рдЗрдЪреНрдЫреБрдХ рдереЗ рдЬрд┐рддрдирд╛ рдХрд┐ рдЗрд╕реЗ рдмрдирд╛рдиреЗ рдореЗрдВ рдореЗрд░реА рджрд┐рд▓рдЪрд╕реНрдкреА рдереАред CASL рдХреЗ рдкрд╛рд╕ рдмрд╣реБрдд рдЕрдЪреНрдЫреЗ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рд╣реИрдВ , рдЖрдк рд╢рд╛рдпрдж рд╡рд╣рд╛рдБ рдмрд╣реБрдд рд╕рд╛рд░реА рдЙрдкрдпреЛрдЧреА рдЬрд╛рдирдХрд╛рд░реА рдкрд╛рдПрдБрдЧреЗ, рд▓реЗрдХрд┐рди рдмреЗрдЭрд┐рдЭрдХ рд╕рд╡рд╛рд▓ рдкреВрдЫ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдЧрдЯрд░ рдЪреИрдЯ рдореЗрдВ рдФрд░ рдЧреАрдердм рдкрд░ рдПрдХ рддрд╛рд░ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП;)