yarn add @malagu/security # 或者 npm i @malagu/security
malagu:
security:
loginUrl: /api/login
loginMethod: POST
logoutUrl: /api/logout
import { Component, Autowired } from '@malagu/core';
import { UserService, UsernameNotFoundError, AccountStatusError, PasswordEncoder } from '@malagu/security/lib/node';
import { User, ElPolicy, PolicyType, AuthorizeType } from '@malagu/security';
import { OrmContext, Transactional } from "@malagu/typeorm/lib/node";
import { UserEntity } from '@microservice/datasource';
/**
* 重写UserService实现自定义登录
* @param username 登录名可以是用户名称(user_name)或者电话(mobile), 优先级:user_name > mobile
*/
@Component({ id: UserService, rebind: true })
export class UserServiceImpl implements UserService<string, User> {
@Autowired(PasswordEncoder)
protected readonly passwordEncoder: PasswordEncoder;
@Transactional({ readOnly: true })
async load(username:string): Promise<User>{
const repo = OrmContext.getRepository(UserEntity);
let user = await repo.findOne({ userName: username })
if (!user) {
user = await repo.findOne({ mobile: username })
}
if (!user) {
throw new UsernameNotFoundError();
}
if(user.state == false){
throw new AccountStatusError();
}
return {
type: "",
username: user.userName,
password: user.password,
policies: [ <ElPolicy>{
type: PolicyType.el,
authorizeType: AuthorizeType.Pre,
el: 'true'
} ],
accountNonExpired: true,
accountNonLocked: true,
credentialsNonExpired: true,
enabled: true
}
}
}
import { Component, Autowired } from '@malagu/core';
import { HttpStatus } from '@malagu/web';
import { ErrorHandler, Context, RedirectStrategy } from '@malagu/web/lib/node';
import { AuthenticationErrorHandler,
AUTHENTICATION_ERROR_HANDLER_PRIORITY,
AuthenticationError } from '@malagu/security/lib/node'
@Component({ id: AuthenticationErrorHandler, rebind: true })
export class AuthenticationErrorHandlerImpl implements ErrorHandler{
readonly priority: number = AUTHENTICATION_ERROR_HANDLER_PRIORITY;
@Autowired(RedirectStrategy)
protected readonly redirectStrategy: RedirectStrategy;
canHandle(ctx: Context, err: Error): Promise<boolean> {
return Promise.resolve(err instanceof AuthenticationError);
}
async handle(ctx: Context, err: AuthenticationError): Promise<void> {
let message = "";
switch (err.name) {
case "UsernameNotFoundError":
ctx.response.statusCode = HttpStatus.FORBIDDEN;
message = "用户不存在";
break;
case "BadCredentialsError":
ctx.response.statusCode = HttpStatus.FORBIDDEN;
message = "用户密码错误";
break;
case "AccountStatusError":
ctx.response.statusCode = HttpStatus.FORBIDDEN;
message = "用户被冻结";
break;
case "AuthenticationError":
ctx.response.statusCode = HttpStatus.UNAUTHORIZED;
message = "用户没有访问权限,需要进行身份认证";
break;
default:
ctx.response.statusCode = HttpStatus.UNAUTHORIZED;
message = err.message;
break;
}
ctx.response.end(message);
}
}
import { Component } from '@malagu/core';
import { HttpStatus } from '@malagu/web';
import { AuthenticationSuccessHandler, Authentication } from '@malagu/security/lib/node'
import { Context } from '@malagu/web/lib/node'
@Component({ id: AuthenticationSuccessHandler, rebind: true })
export class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
async onAuthenticationSuccess(authentication: Authentication): Promise<void> {
Context.getResponse().statusCode = HttpStatus.OK;
Context.getResponse().body = JSON.stringify({ username: authentication.name });
}
}
import { LogoutSuccessHandler, LOGOUT_SUCCESS_HANDLER_PRIORITY } from '@malagu/security/lib/node';
import { Component } from '@malagu/core';
import { HttpStatus } from '@malagu/web';
import { Context } from '@malagu/web/lib/node';
@Component({id: LogoutSuccessHandler, rebind: true })
export class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
readonly priority = LOGOUT_SUCCESS_HANDLER_PRIORITY;
async onLogoutSuccess(): Promise<void> {
Context.getResponse().statusCode = HttpStatus.OK;
Context.getResponse().body = "登出成功";
}
}
@Controller("user")
@Authenticated()
export class UserController {
@Autowired(UserInfoService)
protected userInfoService: UserInfoService;
... ...
}
也可以在指定的接口上使用
@Get("/:userId")
@Json()
@Authenticated()
async getUserInfo(@Param("userId") userId: number){
const result = await this.userInfoService.getUserInfo(userId);
return result
}
至此,@malagu/security的核心代码就已经完成。在module.ts文件引用,运行项目我们就可以进行的调试了。由于登录逻辑都交由组件处理了,malagu的认证授权还是比较简单的。
*** 本文为学习分享文章,如有错误欢迎指正!思考内容欢迎各位大佬答疑解惑。***