导言
- 本文已参加「开源摘星打算」,欢送正在浏览的你退出。流动链接: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实现单点登录吗?
本文为学习类文章,如有谬误欢送斧正!思考内容欢送各位大佬答疑解惑。