Skip to content

Commit

Permalink
Implements Authorization in Resolvers
Browse files Browse the repository at this point in the history
  • Loading branch information
gamarcos committed Jul 28, 2018
1 parent fc900a5 commit 4c2736d
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 50 deletions.
7 changes: 4 additions & 3 deletions src/graphql/composable/auth.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import { ComposableResolver } from "./composable.resolver"
import { ResolverContext } from "../../interfaces/ResolverContextInterface"
import { verifyTokenResolver } from "./verify-token.resolver";

export const authResolver: ComposableResolver<any, ResolverContext> =
(resolver: GraphQLFieldResolver<any, ResolverContext>): GraphQLFieldResolver<any, ResolverContext> => {

return(parent, args, context: ResolverContext, info) => {
if (context.user || context.authorization) {
if (context.authUser || context.authorization) {
return resolver(parent, args, context, info)
}

throw new Error('Unauthorized! Token not provided!')
}

}
}
export const authResolvers = [authResolver, verifyTokenResolver]
25 changes: 16 additions & 9 deletions src/graphql/resource/comment/comment.resovers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { GraphQLResolveInfo } from "../../../../node_modules/@types/graphql"
import { DbConnection } from "../../../interfaces/DbConnectionInterface"
import { Transaction } from "../../../../node_modules/@types/sequelize"
import { CommentInterface } from "../../../models/CommentModel"
import { handleError } from "../../../utils/utils"
import { handleError, throwError } from "../../../utils/utils"
import { compose } from "../../composable/composable.resolver";
import { authResolvers } from "../../composable/auth.resolver";
import { AuthUser } from "../../../interfaces/AuthUserInterface";

export const commentResolvers = {
Comment: {
Expand Down Expand Up @@ -30,36 +33,40 @@ export const commentResolvers = {
},

Mutation: {
createComment: (parent, {input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
createComment: compose(...authResolvers)((parent, {input}, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
input.user = authUser.id
return db.sequelize.transaction((t: Transaction) => {
return db.Comment.create(input, {transaction: t})
})
.catch(handleError)
},
}),

updateComment: (parent, {id, input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
updateComment: compose(...authResolvers)((parent, {id, input}, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
id = parseInt(id)
return db.sequelize.transaction((t: Transaction) => {
return db.Comment
.findById(id)
.then((comment: CommentInterface )=> {
if (!comment) throw new Error(`Comment with ${id} not found!`)
throwError(!comment, `Comment with ${id} not found!`)
throwError(comment.get('user') != authUser.id, `Unauthorized! You can only edit comments by yourself!`)
input.user = authUser.id
return comment.update(input, {transaction: t})
})
}).catch(handleError)
},
}),

deleteComment: (parent, {id, input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
deleteComment: compose(...authResolvers)((parent, {id, input}, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
id = parseInt(id)
return db.sequelize.transaction((t: Transaction) => {
return db.Comment
.findById(id)
.then((comment: CommentInterface )=> {
if (!comment) throw new Error(`Comment with ${id} not found!`)
throwError(!comment, `Comment with ${id} not found!`)
throwError(comment.get('user') != authUser.id, `Unauthorized! You can only edit comments by yourself!`)
return comment.destroy({transaction: t})
.then(comment => !!comment)
})
}).catch(handleError)
}
})
}
}
1 change: 0 additions & 1 deletion src/graphql/resource/comment/comment.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const commentTypes = `
input CommentInput {
comment: String!
post: Int!
user: Int!
}
`
Expand Down
27 changes: 17 additions & 10 deletions src/graphql/resource/post/post.resovers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { GraphQLResolveInfo } from "graphql"
import { DbConnection } from "../../../interfaces/DbConnectionInterface"
import { PostInterface } from "../../../models/PostModel"
import { Transaction } from "../../../../node_modules/@types/sequelize"
import { handleError } from "../../../utils/utils"
import { handleError, throwError } from "../../../utils/utils"
import { compose } from "../../composable/composable.resolver";
import { authResolvers } from "../../composable/auth.resolver";
import { AuthUser } from "../../../interfaces/AuthUserInterface";

export const postResolvers = {

Expand Down Expand Up @@ -39,43 +42,47 @@ export const postResolvers = {
return db.Post
.findById(id)
.then((post: PostInterface) => {
if (!post) throw new Error(`Post with id ${id} not found!`)
throwError(!post, `Post with id ${id} not found!`)
return post
}).catch(handleError)

}
},

Mutation: {
createPost: (parent, { input }, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
createPost: compose(...authResolvers)((parent, { input }, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
input.author = authUser.id
return db.sequelize.transaction((t: Transaction) => {
return db.Post.create(input, {transaction: t})
}).catch(handleError)
},
}),

updatePost: (parent, {id, input }, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
updatePost: compose(...authResolvers)((parent, {id, input }, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
id = parseInt(id)
return db.sequelize.transaction((t: Transaction) => {
return db.Post
.findById(id)
.then((post: PostInterface) => {
if (!post) throw new Error(`Post with id ${id} not found!`)
throwError(!post, `Post with id ${id} not found!`)
throwError(post.get('author') != authUser.id, `Unauthorized! You can only edit posts by yourself!`)
input.author = authUser.id
return post.update(input, {transaction: t})
})
}).catch(handleError)
},
}),

deletePost: (parent, {id}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
deletePost: compose(...authResolvers)((parent, {id}, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
id = parseInt(id)
return db.sequelize.transaction((t: Transaction) => {
return db.Post
.findById(id)
.then((post: PostInterface) => {
if (!post) throw new Error(`Post with id ${id} not found!`)
throwError(!post, `Post with id ${id} not found!`)
throwError(post.get('author') != authUser.id, `Unauthorized! You can only edit posts by yourself!`)
return post.destroy({transaction: t})
.then(post => !!post)
})
}).catch(handleError)
}
})
}
}
1 change: 0 additions & 1 deletion src/graphql/resource/post/post.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const postTypes = `
title: String!
content: String!
photo: String!
author: Int!
}
`
Expand Down
55 changes: 32 additions & 23 deletions src/graphql/resource/user/user.resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { GraphQLResolveInfo } from "../../../../node_modules/@types/graphql"
import { Transaction } from "../../../../node_modules/@types/sequelize"

import { AuthUser } from "../../../interfaces/AuthUserInterface"
import { DbConnection } from "../../../interfaces/DbConnectionInterface"
import { UserInstance } from "../../../models/UserModel"
import { handleError } from "../../../utils/utils"
import { compose } from "../../composable/composable.resolver";
import { authResolver } from "../../composable/auth.resolver";
import { handleError, throwError } from "../../../utils/utils"
import { compose } from "../../composable/composable.resolver"
import { authResolvers } from "../../composable/auth.resolver";

//Refactor Functions, Very Verbose

export const userResolvers = {

Expand All @@ -21,23 +24,32 @@ export const userResolvers = {
},

Query: {
users: compose(authResolver)((parent, {first = 10, offset = 0}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
users: (parent, {first = 10, offset = 0}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
return db.User
.findAll({
limit: first,
offset: offset
}).catch(handleError)
}),
},

user: (parent, {id}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
id = parseInt(id)
return db.User
.find(id)
.then((user: UserInstance) => {
if (!user) throw new Error(`User with ${id} not found!`)
throwError(!user, `User with ${id} not found!`)
return user
}).catch(handleError)
}
},

currentUser: compose(...authResolvers)((parent, args, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
return db.User
.findById(authUser.id)
.then((user: UserInstance) => {
throwError(!user, `User with ${authUser.id} not found!`)
return user
}).catch(handleError)
})
},

Mutation: {
Expand All @@ -48,43 +60,40 @@ export const userResolvers = {
}).catch(handleError)
},

updateUser: (parent, {id, input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
id = parseInt(id)
updateUser: compose(...authResolvers)((parent, {input}, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
return db.sequelize.transaction((t: Transaction) => {
return db.User
.findById(id)
.findById(authUser.id)
.then((user: UserInstance) => {
if (!user) throw new Error(`User with ${id} not found!`)
throwError(!user, `User with ${authUser.id} not found!`)
return user.update(input, {transaction: t})
})
}).catch(handleError)
},
}),

updateUserPassword: (parent, {id, input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
id = parseInt(id)
updateUserPassword: compose(...authResolvers)((parent, {input}, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
return db.sequelize.transaction((t: Transaction) => {
return db.User
.findById(id)
.findById(authUser.id)
.then((user: UserInstance) => {
if (!user) throw new Error(`User with ${id} not found!`)
throwError(!user, `User with ${authUser.id} not found!`)
return user.update(input, {transaction: t})
.then((user: UserInstance) => !!user)
})
}).catch(handleError)
},
}),

deleteUser: (parent, {id}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => {
id = parseInt(id)
deleteUser: compose(...authResolvers)((parent, args, {db, authUser}: {db: DbConnection, authUser: AuthUser}, info: GraphQLResolveInfo) => {
return db.sequelize.transaction((t: Transaction) => {
return db.User
.findById(id)
.findById(authUser.id)
.then((user: UserInstance) => {
if (!user) throw new Error(`User with ${id} not found!`)
throwError(!user, `User with ${authUser.id} not found!`)
return user.destroy({transaction: t})
.then(user => !!user)
})
}).catch(handleError)
}
}
})

}
}
2 changes: 1 addition & 1 deletion src/graphql/resource/user/user.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const userMutations = `
createUser(input: UserCreateInput!): User
updateUser(input: UserUpdateInput!): User
updateUserPassword(input: UserUpdatePasswordInput!): Boolean
deleteUser(id: ID!): Boolean
deleteUser: Boolean
`

export {
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/ResolverContextInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export interface ResolverContext {

db?: DbConnection
authorization?: String
user?: AuthUser
authUser?: AuthUser

}
2 changes: 1 addition & 1 deletion src/middlewares/extract-jwt.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const extractJwtMiddleware = (): RequestHandler => {
}).then((user: UserInstance) => {

if (user) {
req['context']['user'] = {
req['context']['authUser'] = {
id: user.get('id'),
email: user.get('email')
}
Expand Down
6 changes: 6 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ export const handleError = (error: Error) => {
return Promise.reject(new Error(errorMessage))
}

export const throwError = (condition: boolean, message: string): void => {
if (condition) {
throw new Error(message)
}
}

export const JWT_SECRET: string = process.env.JWT_SECRET

0 comments on commit 4c2736d

Please sign in to comment.