导言

  • 本文已参加「开源摘星打算」,欢送正在浏览的你退出。流动链接:https://github.com/weopenproj...
  • malagu的认证与受权参考spring-security思维,具体介绍请移步官网文档。malagu除了根本的security外提供了ODIC 的认证和 OAuth2.0 的受权能力,本文次要介绍@malagu/security组件的根本利用实际。

认证与受权组件 @malagu/security的简略利用

  • 1.增加组件
    在我的项目中援用@malagu/security组件

    yarn add @malagu/security # 或者 npm i @malagu/security
  • 2.重写loginUrl和logoutUrl
    定义登录和登记接口和申请形式

    malagu:security:  loginUrl: /api/login  loginMethod: POST      logoutUrl: /api/logout
  • 3.重写UserService实现自定义登录
    注册用户时明码须要应用PasswordEncoder生成;
    咱们只需将用户和明码在load()中赋值给security组件User即可,校验比对逻辑交由@malagu/security组件实现。

    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      }  }}
  • 4.重写认证失败处理器AuthenticationErrorHandler

    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);  }}
  • 5.重写认证胜利处理器AuthenticationSuccessHandler
    非必须,不重写将跳转到首页

    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 });  }}
  • 6.从新登出处理器LogoutSuccessHandler
    非必须,不重写将跳转到登录页

    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 = "登出胜利";  }}
  • 7.@Authenticated的应用
    能够在controller类上应用,这样该类下的所有凋谢接口都须要鉴权

    @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    }
  • 8.除了@Authenticated,malagu还提供了用于权限管制的装璜器@PreAuthorize以及匿名@Anonymous

结语

至此,@malagu/security的外围代码就曾经实现。在module.ts文件援用,运行我的项目咱们就能够进行的调试了。因为登录逻辑都交由组件解决了,malagu的认证受权还是比较简单的。

思考

  • @malagu/security的原理是怎么的?
  • UserService中返回体User各属性的含意?
  • 登录有效期怎么设置?
  • 能够应用@malagu/security实现单点登录吗?

本文为学习类文章,如有谬误欢送斧正!思考内容欢送各位大佬答疑解惑。