-
-
Notifications
You must be signed in to change notification settings - Fork 642
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(server): new authentication implements (#897)
* feat(authentication): new authentication implements * feat(authentication): impl bind username and phone * feat(authentication): adjust to code review feedbacks * feat(authentication): modify code according to cr-gpt --------- Co-authored-by: maslow <wangfugen@126.com>
- Loading branch information
Showing
25 changed files
with
1,508 additions
and
7 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { AuthenticationService } from './authentication.service' | ||
import { Body, Controller, Get, Post, Req, UseGuards } from '@nestjs/common' | ||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' | ||
import { ResponseUtil } from 'src/utils/response' | ||
import { JwtAuthGuard } from './jwt.auth.guard' | ||
import { BindUsernameDto } from './dto/bind-username.dto' | ||
import { IRequest } from 'src/utils/interface' | ||
import { BindPhoneDto } from './dto/bind-phone.dto' | ||
import { SmsService } from './phone/sms.service' | ||
import { SmsVerifyCodeType } from '@prisma/client' | ||
import { UserService } from 'src/user/user.service' | ||
|
||
@ApiTags('Authentication - New') | ||
@Controller('auth') | ||
export class AuthenticationController { | ||
constructor( | ||
private readonly authenticationService: AuthenticationService, | ||
private readonly smsService: SmsService, | ||
private readonly userService: UserService, | ||
) {} | ||
|
||
/** | ||
* Auth providers | ||
*/ | ||
@ApiOperation({ summary: 'Auth providers' }) | ||
@ApiResponse({ type: ResponseUtil }) | ||
@Get('providers') | ||
async getProviders() { | ||
const providers = await this.authenticationService.getProviders() | ||
return ResponseUtil.ok(providers) | ||
} | ||
|
||
/** | ||
* Bind phone | ||
*/ | ||
@ApiOperation({ summary: 'Bind username' }) | ||
@ApiResponse({ type: ResponseUtil }) | ||
@UseGuards(JwtAuthGuard) | ||
@Post('bind/phone') | ||
async bindPhone(@Body() dto: BindPhoneDto, @Req() req: IRequest) { | ||
const { phone, code } = dto | ||
// check code valid | ||
const err = await this.smsService.validCode( | ||
phone, | ||
code, | ||
SmsVerifyCodeType.Bind, | ||
) | ||
if (err) { | ||
return ResponseUtil.error(err) | ||
} | ||
|
||
// check phone if have already been bound | ||
const user = await this.userService.find(phone) | ||
if (user) { | ||
return ResponseUtil.error('phone already been bound') | ||
} | ||
|
||
// bind phone | ||
await this.userService.updateUser({ | ||
where: { | ||
id: req.user.id, | ||
}, | ||
data: { | ||
phone, | ||
}, | ||
}) | ||
} | ||
|
||
/** | ||
* Bind username, not support bind existed username | ||
*/ | ||
@ApiOperation({ summary: 'Bind username' }) | ||
@ApiResponse({ type: ResponseUtil }) | ||
@UseGuards(JwtAuthGuard) | ||
@Post('bind/username') | ||
async bindUsername(@Body() dto: BindUsernameDto, @Req() req: IRequest) { | ||
const { username, phone, code } = dto | ||
|
||
// check code valid | ||
const err = await this.smsService.validCode( | ||
phone, | ||
code, | ||
SmsVerifyCodeType.Bind, | ||
) | ||
if (err) { | ||
return ResponseUtil.error(err) | ||
} | ||
|
||
// check username if have already been bound | ||
const user = await this.userService.find(username) | ||
if (user) { | ||
return ResponseUtil.error('username already been bound') | ||
} | ||
|
||
// bind username | ||
await this.userService.updateUser({ | ||
where: { | ||
id: req.user.id, | ||
}, | ||
data: { | ||
username, | ||
}, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { JwtService } from '@nestjs/jwt' | ||
import { PrismaService } from 'src/prisma/prisma.service' | ||
import { Injectable, Logger } from '@nestjs/common' | ||
import { AuthProviderState, User } from '@prisma/client' | ||
import { | ||
PASSWORD_AUTH_PROVIDER_NAME, | ||
PHONE_AUTH_PROVIDER_NAME, | ||
} from 'src/constants' | ||
|
||
@Injectable() | ||
export class AuthenticationService { | ||
logger: Logger = new Logger(AuthenticationService.name) | ||
constructor( | ||
private readonly prismaService: PrismaService, | ||
private readonly jwtService: JwtService, | ||
) {} | ||
|
||
/** | ||
* Get all auth provides | ||
* @returns | ||
*/ | ||
async getProviders() { | ||
return await this.prismaService.authProvider.findMany({ | ||
where: { state: AuthProviderState.Enabled }, | ||
select: { | ||
id: false, | ||
name: true, | ||
bind: true, | ||
register: true, | ||
default: true, | ||
state: true, | ||
config: false, | ||
}, | ||
}) | ||
} | ||
|
||
async getPhoneProvider() { | ||
return await this.getProvider(PHONE_AUTH_PROVIDER_NAME) | ||
} | ||
|
||
async getPasswdProvider() { | ||
return await this.getProvider(PASSWORD_AUTH_PROVIDER_NAME) | ||
} | ||
|
||
// Get auth provider by name | ||
async getProvider(name: string) { | ||
return await this.prismaService.authProvider.findUnique({ | ||
where: { name }, | ||
}) | ||
} | ||
|
||
/** | ||
* Get access token by user | ||
* @param user | ||
* @returns | ||
*/ | ||
getAccessTokenByUser(user: User): string { | ||
const payload = { | ||
sub: user.id, | ||
} | ||
const token = this.jwtService.sign(payload) | ||
return token | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { ApiProperty } from '@nestjs/swagger' | ||
import { IsNotEmpty, IsString, Length, Matches } from 'class-validator' | ||
|
||
export class BindPhoneDto { | ||
@ApiProperty({ | ||
description: 'phone number', | ||
example: '13805718888', | ||
}) | ||
@IsString() | ||
@IsNotEmpty() | ||
@Matches(/^1[3-9]\d{9}$/) | ||
phone: string | ||
|
||
@ApiProperty({ | ||
description: 'sms verify code', | ||
example: '032476', | ||
}) | ||
@IsNotEmpty() | ||
@Length(6, 6) | ||
code: string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { ApiProperty } from '@nestjs/swagger' | ||
import { IsNotEmpty, IsString, Length, Matches } from 'class-validator' | ||
|
||
export class BindUsernameDto { | ||
@ApiProperty({ | ||
description: 'username', | ||
example: 'laf-user', | ||
}) | ||
@IsString() | ||
@IsNotEmpty() | ||
@Length(3, 64) | ||
username: string | ||
|
||
@ApiProperty({ | ||
description: 'phone', | ||
example: '13805718888', | ||
}) | ||
@IsString() | ||
@IsNotEmpty() | ||
@Matches(/^1[3-9]\d{9}$/) | ||
phone: string | ||
|
||
@ApiProperty({ | ||
description: 'sms verify code', | ||
example: '032476', | ||
}) | ||
@IsNotEmpty() | ||
@Length(6, 6) | ||
code: string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { ApiProperty } from '@nestjs/swagger' | ||
import { SmsVerifyCodeType } from '@prisma/client' | ||
import { IsEnum, IsNotEmpty, IsString, Length, Matches } from 'class-validator' | ||
|
||
export class PasswdResetDto { | ||
@ApiProperty({ | ||
description: 'new password, 8-64 characters', | ||
example: 'laf-user-password', | ||
}) | ||
@IsString() | ||
@IsNotEmpty() | ||
@Length(8, 64) | ||
password: string | ||
|
||
@ApiProperty({ | ||
description: 'phone', | ||
example: '13805718888', | ||
}) | ||
@IsString() | ||
@Matches(/^1[3-9]\d{9}$/) | ||
phone: string | ||
|
||
@ApiProperty({ | ||
description: 'verify code', | ||
example: '032456', | ||
}) | ||
@IsString() | ||
@Length(6, 6) | ||
code: string | ||
|
||
@ApiProperty({ | ||
description: 'type', | ||
example: 'ResetPassword', | ||
}) | ||
@IsEnum(SmsVerifyCodeType) | ||
type: SmsVerifyCodeType | ||
} |
Oops, something went wrong.