feat: auth jwt, permissions, login ui (wip)
This commit is contained in:
54
server/graph/directives/auth.js
Normal file
54
server/graph/directives/auth.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const { SchemaDirectiveVisitor } = require('graphql-tools')
|
||||
const { defaultFieldResolver } = require('graphql')
|
||||
|
||||
class AuthDirective extends SchemaDirectiveVisitor {
|
||||
visitObject(type) {
|
||||
this.ensureFieldsWrapped(type)
|
||||
type._requiredAuthScopes = this.args.requires
|
||||
}
|
||||
// Visitor methods for nested types like fields and arguments
|
||||
// also receive a details object that provides information about
|
||||
// the parent and grandparent types.
|
||||
visitFieldDefinition(field, details) {
|
||||
this.ensureFieldsWrapped(details.objectType)
|
||||
field._requiredAuthScopes = this.args.requires
|
||||
}
|
||||
|
||||
visitArgumentDefinition(argument, details) {
|
||||
this.ensureFieldsWrapped(details.objectType)
|
||||
argument._requiredAuthScopes = this.args.requires
|
||||
}
|
||||
|
||||
ensureFieldsWrapped(objectType) {
|
||||
// Mark the GraphQLObjectType object to avoid re-wrapping:
|
||||
if (objectType._authFieldsWrapped) return
|
||||
objectType._authFieldsWrapped = true
|
||||
|
||||
const fields = objectType.getFields()
|
||||
|
||||
Object.keys(fields).forEach(fieldName => {
|
||||
const field = fields[fieldName]
|
||||
const { resolve = defaultFieldResolver } = field
|
||||
field.resolve = async function (...args) {
|
||||
// Get the required scopes from the field first, falling back
|
||||
// to the objectType if no scopes is required by the field:
|
||||
const requiredScopes = field._requiredAuthScopes || objectType._requiredAuthScopes
|
||||
|
||||
if (!requiredScopes) {
|
||||
return resolve.apply(this, args)
|
||||
}
|
||||
|
||||
const context = args[2]
|
||||
console.info(context.req.user)
|
||||
// const user = await getUser(context.headers.authToken)
|
||||
// if (!user.hasRole(requiredScopes)) {
|
||||
// throw new Error('not authorized')
|
||||
// }
|
||||
|
||||
return resolve.apply(this, args)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AuthDirective
|
@@ -31,6 +31,10 @@ resolversObj.forEach(resolver => {
|
||||
_.merge(resolvers, resolver)
|
||||
})
|
||||
|
||||
// Directives
|
||||
|
||||
let schemaDirectives = autoload(path.join(WIKI.SERVERPATH, 'graph/directives'))
|
||||
|
||||
// Live Trail Logger (admin)
|
||||
|
||||
let LiveTrailLogger = winston.transports.LiveTrailLogger = function (options) {
|
||||
@@ -55,5 +59,6 @@ WIKI.logger.info(`GraphQL Schema: [ OK ]`)
|
||||
|
||||
module.exports = {
|
||||
typeDefs,
|
||||
resolvers
|
||||
resolvers,
|
||||
schemaDirectives
|
||||
}
|
||||
|
@@ -3,8 +3,6 @@ const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const graphHelper = require('../../helpers/graph')
|
||||
|
||||
// const getFieldNames = require('graphql-list-fields')
|
||||
|
||||
/* global WIKI */
|
||||
|
||||
module.exports = {
|
||||
@@ -16,7 +14,7 @@ module.exports = {
|
||||
},
|
||||
AuthenticationQuery: {
|
||||
async strategies(obj, args, context, info) {
|
||||
let strategies = await WIKI.models.authentication.getStrategies()
|
||||
let strategies = await WIKI.models.authentication.getStrategies(args.isEnabled)
|
||||
strategies = strategies.map(stg => {
|
||||
const strategyInfo = _.find(WIKI.data.authentication, ['key', stg.key]) || {}
|
||||
return {
|
||||
@@ -34,8 +32,6 @@ module.exports = {
|
||||
}, []), 'key')
|
||||
}
|
||||
})
|
||||
if (args.filter) { strategies = graphHelper.filter(strategies, args.filter) }
|
||||
if (args.orderBy) { strategies = graphHelper.orderBy(strategies, args.orderBy) }
|
||||
return strategies
|
||||
}
|
||||
},
|
||||
|
@@ -16,8 +16,7 @@ extend type Mutation {
|
||||
|
||||
type AuthenticationQuery {
|
||||
strategies(
|
||||
filter: String
|
||||
orderBy: String
|
||||
isEnabled: Boolean
|
||||
): [AuthenticationStrategy]
|
||||
}
|
||||
|
||||
@@ -54,16 +53,18 @@ type AuthenticationStrategy {
|
||||
description: String
|
||||
useForm: Boolean!
|
||||
logo: String
|
||||
color: String
|
||||
website: String
|
||||
icon: String
|
||||
config: [KeyValuePair]
|
||||
config: [KeyValuePair] @auth(requires: ["manage:system"])
|
||||
selfRegistration: Boolean!
|
||||
domainWhitelist: [String]!
|
||||
autoEnrollGroups: [Int]!
|
||||
domainWhitelist: [String]! @auth(requires: ["manage:system"])
|
||||
autoEnrollGroups: [Int]! @auth(requires: ["manage:system"])
|
||||
}
|
||||
|
||||
type AuthenticationLoginResponse {
|
||||
responseResult: ResponseStatus
|
||||
jwt: String
|
||||
tfaRequired: Boolean
|
||||
tfaLoginToken: String
|
||||
}
|
||||
|
@@ -13,6 +13,10 @@ enum RightRole {
|
||||
manage
|
||||
}
|
||||
|
||||
# DIRECTIVES
|
||||
|
||||
directive @auth(requires: [String]) on QUERY | FIELD_DEFINITION | ARGUMENT_DEFINITION
|
||||
|
||||
# TYPES
|
||||
|
||||
type KeyValuePair {
|
||||
|
Reference in New Issue
Block a user