feat(fullstack): Add JWT validation
This commit is contained in:
@@ -8,7 +8,10 @@ info:
|
|||||||
email: denis.lugowski@gmail.com
|
email: denis.lugowski@gmail.com
|
||||||
|
|
||||||
servers:
|
servers:
|
||||||
- url: /
|
- url: http://localhost:8080
|
||||||
|
|
||||||
|
security:
|
||||||
|
- bearerAuth: []
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/application-forms:
|
/application-forms:
|
||||||
@@ -592,6 +595,12 @@ paths:
|
|||||||
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
|
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
|
||||||
|
|
||||||
components:
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
bearerAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
####### UserDto #######
|
####### UserDto #######
|
||||||
UserDto:
|
UserDto:
|
||||||
|
|||||||
@@ -24,9 +24,12 @@ dependencies {
|
|||||||
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
|
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
||||||
implementation 'org.liquibase:liquibase-core'
|
implementation 'org.liquibase:liquibase-core'
|
||||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.4'
|
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6'
|
||||||
implementation 'org.springdoc:springdoc-openapi-ui:1.8.0'
|
implementation 'org.springdoc:springdoc-openapi-ui:1.8.0'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
// https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html#oauth2-resource-server-access-token-jwt
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
runtimeOnly 'com.h2database:h2'
|
runtimeOnly 'com.h2database:h2'
|
||||||
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
|
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.betriebsratkanzlei.legalconsenthub.config
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.invoke
|
||||||
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder
|
||||||
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder
|
||||||
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
class SecurityConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
http {
|
||||||
|
csrf { disable() }
|
||||||
|
authorizeHttpRequests {
|
||||||
|
authorize("/swagger-ui/**", permitAll)
|
||||||
|
authorize("/v3/**", permitAll)
|
||||||
|
authorize(anyRequest, authenticated)
|
||||||
|
}
|
||||||
|
oauth2ResourceServer {
|
||||||
|
jwt { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun jwtDecoder(): JwtDecoder {
|
||||||
|
return NimbusJwtDecoder.withJwkSetUri("http://192.168.178.105:3001/api/auth/jwks")
|
||||||
|
.jwsAlgorithm(SignatureAlgorithm.ES512).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,14 @@ spring:
|
|||||||
order_inserts: true
|
order_inserts: true
|
||||||
enable_lazy_load_no_trans: true
|
enable_lazy_load_no_trans: true
|
||||||
|
|
||||||
|
# security:
|
||||||
|
# oauth2:
|
||||||
|
# resourceserver:
|
||||||
|
# jwt:
|
||||||
|
# issuer-uri: http://192.168.178.105:3001
|
||||||
|
# jwk-set-uri: http://192.168.178.105:3001/api/auth/jwks
|
||||||
|
# jws-algorithms: ES512
|
||||||
|
|
||||||
liquibase:
|
liquibase:
|
||||||
enabled: true
|
enabled: true
|
||||||
drop-first: false
|
drop-first: false
|
||||||
@@ -31,3 +39,10 @@ spring:
|
|||||||
sql:
|
sql:
|
||||||
init:
|
init:
|
||||||
platform: h2
|
platform: h2
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org:
|
||||||
|
springframework:
|
||||||
|
security: TRACE
|
||||||
|
oauth2: TRACE
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export function useApplicationFormApi() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const applicationFormApiClient = new ApplicationFormApi(
|
const applicationFormApiClient = new ApplicationFormApi(
|
||||||
new Configuration({ basePath, headers: { Authorization: jwt.value ?? '' } })
|
new Configuration({ basePath, headers: { Authorization: jwt.value ? `Bearer ${jwt.value}` : '' } })
|
||||||
)
|
)
|
||||||
|
|
||||||
async function createApplicationForm(
|
async function createApplicationForm(
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ import { cleanDoubleSlashes, withoutTrailingSlash } from 'ufo'
|
|||||||
export function useApplicationFormTemplateApi() {
|
export function useApplicationFormTemplateApi() {
|
||||||
const appBaseUrl = useRuntimeConfig().app.baseURL
|
const appBaseUrl = useRuntimeConfig().app.baseURL
|
||||||
const { serverApiBaseUrl, serverApiBasePath, clientProxyBasePath } = useRuntimeConfig().public
|
const { serverApiBaseUrl, serverApiBasePath, clientProxyBasePath } = useRuntimeConfig().public
|
||||||
|
const { jwt } = useAuth()
|
||||||
|
|
||||||
const basePath = withoutTrailingSlash(
|
const basePath = withoutTrailingSlash(
|
||||||
cleanDoubleSlashes(import.meta.client ? appBaseUrl + clientProxyBasePath : serverApiBaseUrl + serverApiBasePath)
|
cleanDoubleSlashes(import.meta.client ? appBaseUrl + clientProxyBasePath : serverApiBaseUrl + serverApiBasePath)
|
||||||
)
|
)
|
||||||
|
|
||||||
const applicationFormApiClient = new ApplicationFormTemplateApi(new Configuration({ basePath }))
|
const applicationFormApiClient = new ApplicationFormTemplateApi(
|
||||||
|
new Configuration({ basePath, headers: { Authorization: jwt.value ? `Bearer ${jwt.value}` : '' } })
|
||||||
|
)
|
||||||
|
|
||||||
async function createApplicationFormTemplate(
|
async function createApplicationFormTemplate(
|
||||||
createApplicationFormDto: CreateApplicationFormDto
|
createApplicationFormDto: CreateApplicationFormDto
|
||||||
|
|||||||
@@ -7,7 +7,17 @@ export const auth = betterAuth({
|
|||||||
database: new Database('./sqlite.db'),
|
database: new Database('./sqlite.db'),
|
||||||
emailAndPassword: { enabled: true, autoSignIn: false },
|
emailAndPassword: { enabled: true, autoSignIn: false },
|
||||||
plugins: [
|
plugins: [
|
||||||
jwt(),
|
jwt({
|
||||||
|
jwt: {
|
||||||
|
issuer: 'http://192.168.178.105:3001'
|
||||||
|
},
|
||||||
|
jwks: {
|
||||||
|
keyPairConfig: {
|
||||||
|
// Supported by NimbusJwtDecoder
|
||||||
|
alg: 'ES512'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
organization({
|
organization({
|
||||||
async sendInvitationEmail(data) {
|
async sendInvitationEmail(data) {
|
||||||
console.log('Sending invitation email', data)
|
console.log('Sending invitation email', data)
|
||||||
|
|||||||
Reference in New Issue
Block a user