共计 4707 个字符,预计需要花费 12 分钟才能阅读完成。
导言
- 本文已参加「开源摘星打算」,欢送正在浏览的你退出。流动链接: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 实现单点登录吗?
本文为学习类文章,如有谬误欢送斧正!思考内容欢送各位大佬答疑解惑。
正文完
发表至: typescript
2022-08-09