loopback4出现问题,尤其是当我尝试创建自定义身份验证UserService时。
我尝试定义自己的JWTStrategy
和JWTService
,但是有相同的错误。
我遵循文档(https://loopback.io/doc/en/lb4/JWT-authentication-extension.html#stability-%EF%B8%8Fexperimental%EF%B8%8F),但是在运行API时返回错误
Argument of type 'typeof MyUserService' is not assignable to parameter of type 'Constructor<UserService<User, Credentials>>'.
Construct signature return types 'MyUserService' and 'UserService<User, Credentials>' are incompatible
这是我的要素
PostgreSQL数据库=>用户表
CREATE TABLE public.users (
username CHARACTER VARYING(10) NOT NULL UNIQUE,
password CHARACTER VARYING(255) NOT NULL,
PRIMARY KEY (username)
);
user.model.ts
import {Entity, model, property} from '@loopback/repository';
@model({settings: {strict: false}})
export class MyUser extends Entity {
@property({
type: 'string',
id: true,
generated: false,
required: true,
})
username: string;
@property({
type: 'string',
required: true,
})
password: string;
[prop: string]: any;
constructor(data?: Partial<MyUser>) {
super(data);
}
}
export interface UserRelations {
// describe navigational properties here
}
export type UserWithRelations = MyUser & UserRelations;
user.repository.ts
import {DefaultCrudRepository} from '@loopback/repository';
import {MyUser, UserRelations} from '../models';
import {DbDataSource} from '../datasources';
import {inject} from '@loopback/core';
export class MyUserRepository extends DefaultCrudRepository<
MyUser,
typeof MyUser.prototype.username,
UserRelations
> {
constructor(
@inject('datasources.db') dataSource: DbDataSource,
) {
super(MyUser, dataSource);
}
}
user.service.ts
import {UserService} from '@loopback/authentication';
import {repository} from '@loopback/repository';
import {HttpErrors} from '@loopback/rest';
import {securityId, UserProfile} from '@loopback/security';
import {compare} from 'bcryptjs';
import {MyUser} from '../models';
import {MyUserRepository} from '../repositories';
export type Credentials = {
username: string;
password: string;
}
export class MyUserService implements UserService<MyUser, Credentials> {
constructor(
@repository(MyUserRepository) public userRepository: MyUserRepository
) {}
async verifyCredentials(credentials: Credentials): Promise<MyUser> {
const foundUser = await this.userRepository.findOne({
where: {
username: credentials.username
}
})
if (!foundUser) throw new HttpErrors['NotFound']('Invalid creds');
const isMatch = await compare(credentials.password, foundUser.password);
if (!isMatch) throw new HttpErrors.Unauthorized('Password not match');
return foundUser;
}
convertToUserProfile(user: MyUser): UserProfile {
return {
[securityId]: user.username,
username: user.username
}
}
}
和我的application.ts文件
import {BootMixin} from '@loopback/boot';
import {ApplicationConfig} from '@loopback/core';
import {
RestExplorerBindings,
RestExplorerComponent,
} from '@loopback/rest-explorer';
import {RepositoryMixin} from '@loopback/repository';
import {RestApplication} from '@loopback/rest';
import {ServiceMixin} from '@loopback/service-proxy';
import path from 'path';
import {MySequence} from './sequence';
import {
AuthenticationComponent,
} from '@loopback/authentication';
import {
JWTAuthenticationComponent,
UserServiceBindings
} from '@loopback/authentication-jwt';
import {
DbDataSource
} from './datasources';
import {MyUserService} from './services';
import {MyUserRepository} from './repositories';
export {ApplicationConfig};
export class PsqlTodoApplication extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options: ApplicationConfig = {}) {
super(options);
// Set up the custom sequence
this.sequence(MySequence);
// Set up default home page
this.static('/', path.join(__dirname, '../public'));
// Customize @loopback/rest-explorer configuration here
this.configure(RestExplorerBindings.COMPONENT).to({
path: '/explorer',
});
this.component(RestExplorerComponent);
this.component(AuthenticationComponent);
this.component(JWTAuthenticationComponent);
this.dataSource(DbDataSource, UserServiceBindings.DATASOURCE_NAME);
this.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService); // <= error is here!
this.bind(UserServiceBindings.USER_REPOSITORY).toClass(MyUserRepository);
this.projectRoot = __dirname;
// Customize @loopback/boot Booter Conventions here
this.bootOptions = {
controllers: {
// Customize ControllerBooter Conventions here
dirs: ['controllers'],
extensions: ['.controller.js'],
nested: true,
},
};
}
}
如何使用用户名/密码创建自己的凭据,而不重用@loopback/authentication-jwt
中的凭据?