Skip to content

Commit 7ca4807

Browse files
committed
feat(server): add auth module & jwt auth guard
1 parent 3b24235 commit 7ca4807

File tree

5 files changed

+171
-0
lines changed

5 files changed

+171
-0
lines changed

server/src/auth/auth.module.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Module } from '@nestjs/common'
2+
import { JwtModule } from '@nestjs/jwt'
3+
import { PassportModule } from '@nestjs/passport'
4+
import { AuthService } from './auth.service'
5+
import { JwtStrategy } from './jwt.strategy'
6+
7+
@Module({
8+
imports: [
9+
PassportModule,
10+
JwtModule.register({
11+
// publicKey: process.env.CASDOOR_PUBLIC_CERT,
12+
// signOptions: { expiresIn: '60s' },
13+
}),
14+
],
15+
providers: [AuthService, JwtStrategy],
16+
exports: [AuthService],
17+
})
18+
export class AuthModule {}

server/src/auth/auth.service.spec.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { AuthService } from './auth.service';
3+
4+
describe('AuthService', () => {
5+
let service: AuthService;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
providers: [AuthService],
10+
}).compile();
11+
12+
service = module.get<AuthService>(AuthService);
13+
});
14+
15+
it('should be defined', () => {
16+
expect(service).toBeDefined();
17+
});
18+
});

server/src/auth/auth.service.ts

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { Injectable, Logger } from '@nestjs/common'
2+
import { JwtService } from '@nestjs/jwt'
3+
import { SDK, Config } from 'casdoor-nodejs-sdk'
4+
import * as querystring from 'node:querystring'
5+
6+
@Injectable()
7+
export class AuthService {
8+
private logger = new Logger()
9+
constructor(private jwtService: JwtService) {}
10+
11+
/**
12+
* Get auth config of casdoor
13+
* @returns
14+
*/
15+
getCasdoorConfig() {
16+
const authCfg: Config = {
17+
endpoint: process.env.CASDOOR_ENDPOINT,
18+
clientId: process.env.CASDOOR_CLIENT_ID,
19+
clientSecret: process.env.CASDOOR_CLIENT_SECRET,
20+
certificate: process.env.CASDOOR_PUBLIC_CERT,
21+
orgName: process.env.CASDOOR_ORG_NAME,
22+
}
23+
return authCfg
24+
}
25+
26+
/**
27+
* Create casdoor SDK instance
28+
* @returns
29+
*/
30+
getCasdoorSDK() {
31+
const sdk = new SDK(this.getCasdoorConfig())
32+
return sdk
33+
}
34+
35+
/**
36+
* Get user token by code
37+
* @param code
38+
* @returns
39+
*/
40+
async code2token(code: string): Promise<string> {
41+
try {
42+
const token = await this.getCasdoorSDK().getAuthToken(code)
43+
return token
44+
} catch (error) {
45+
return null
46+
}
47+
}
48+
49+
/**
50+
* Get user info by token
51+
* @param token
52+
* @returns
53+
*/
54+
async getUserInfo(token: string) {
55+
try {
56+
const user = this.jwtService.verify(token, {
57+
publicKey: this.getCasdoorConfig().certificate,
58+
})
59+
Object.keys(user).forEach((key) => {
60+
if (user[key] === '' || user[key] === null) delete user[key]
61+
})
62+
return user
63+
} catch (err) {
64+
this.logger.error(err)
65+
return null
66+
}
67+
}
68+
69+
/**
70+
* Generate login url
71+
* @returns
72+
*/
73+
getSignInUrl(): string {
74+
const authCfg = this.getCasdoorConfig()
75+
const query = {
76+
client_id: authCfg.clientId,
77+
redirect_uri: process.env.CASDOOR_REDIRECT_URI,
78+
response_type: 'code',
79+
scope: 'openid,profile,phone,email',
80+
state: 'casdoor',
81+
}
82+
const encoded_query = querystring.encode(query)
83+
const base_api = `${authCfg.endpoint}/login/oauth/authorize`
84+
const url = `${base_api}?${encoded_query}`
85+
return url
86+
}
87+
88+
/**
89+
* Generate register url
90+
* @returns
91+
*/
92+
getSignUpUrl(): string {
93+
const authCfg = this.getCasdoorConfig()
94+
const app_name = process.env.CASDOOR_APP_NAME
95+
const url = `${authCfg.endpoint}/signup/${app_name}`
96+
return url
97+
}
98+
}

server/src/auth/jwt-auth.guard.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Injectable } from '@nestjs/common'
2+
import { AuthGuard } from '@nestjs/passport'
3+
4+
@Injectable()
5+
export class JwtAuthGuard extends AuthGuard('jwt') {}

server/src/auth/jwt.strategy.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Injectable } from '@nestjs/common'
2+
import { PassportStrategy } from '@nestjs/passport'
3+
import { ExtractJwt, Strategy } from 'passport-jwt'
4+
5+
@Injectable()
6+
export class JwtStrategy extends PassportStrategy(Strategy) {
7+
constructor() {
8+
super({
9+
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
10+
ignoreExpiration: false,
11+
secretOrKey: process.env.CASDOOR_PUBLIC_CERT,
12+
})
13+
}
14+
15+
/**
16+
* Turn payload to user object
17+
* @param payload
18+
* @returns
19+
*/
20+
async validate(payload: any) {
21+
return {
22+
id: payload.sub,
23+
owner: payload.owner,
24+
username: payload.name,
25+
displayName: payload.displayName,
26+
email: payload.email,
27+
avatar: payload.avatar,
28+
emailVerified: payload.emailVerified,
29+
phone: payload.phone,
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)