== Други теми (Перформанси, безбедност) == === Безбедност === * Апликацијата користи Spring Security што е докажан стандард за сетирање на безбедност во апликациите. * Се користи дозволување на клиент кој може да праќа барања до backend {{{ config.setAllowedOrigins(List.of("http://localhost:5173")); }}} * Само рутата за логирање на корисници е дозволена за целата јавност, другите рути бараат автентикација {{{ .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/login").permitAll() .anyRequest().authenticated() ) }}} * Сите корисници се креирани од директор админ и нема стандардна регистрација. = Хеширање на лозинки (Заштита на податоци) = Апликацијата користи BCryptPasswordEncoder како начин за хеширање на лозинки. {{{ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } Кој потоа се користи при хеширање: String encodedPass = passwordEncoder.encode( blagajnikRequestDTO.getLozinka()); }}} = Авторизација (Role-Based Access Control) = Апликацијата користи Roles за дозвола на пристап на некоја активност. Исто така се користи и method security т.е. се користи **@PreAuthorize** анотацијата за заштита на рутите: {{{ @PreAuthorize("hasRole('DIREKTOR_ADMIN')") @GetMapping public ResponseEntity> getAllKlasovi(){ List klasovi = this.klasService.getAllKlasovi(); return new ResponseEntity<>(klasovi, HttpStatus.OK); } @GetMapping("/{classId}/students") @PreAuthorize("hasAnyRole('KLASEN_RAKOVODITEL','DIREKTOR_ADMIN', 'PREDMETEN_NASTAVNIK', 'RODITEL')") public ResponseEntity> getAllStudentsWhoAreInTheSameClass(@PathVariable UUID classId){ List getAllStudentsWhoAreInTheSameClass = this.klasService.getAllStudentsWhoAreInTheSameClass(classId); return new ResponseEntity<>(getAllStudentsWhoAreInTheSameClass, HttpStatus.OK); } }}} = Користење на сесии = Апликацијата користи сесии и сесиско колаче за заштита од менување на податоците од корисник. {{{ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) ); }}} Но, и автоматско бришење на сесиското колаче при одјава: {{{ .logout(logout->logout .logoutUrl("/api/auth/logout") .deleteCookies("JSESSIONID") .logoutSuccessHandler((request, response, authentication) -> { response.setStatus(200); }) }}} = Спречување на SQL Injection = За извршување на SQL прашањата, користиме binding. Односно Spring Boot ги третира овие параметри како податоци а не како извршен код. Дел од кодот: {{{ @Modifying @Transactional @Query(nativeQuery = true, value = "INSERT INTO Usna_Ocenka (id, tema, osvoeni_poeni, max_poeni, vid_isprasuvanje) VALUES( :id,:tema, :osvoeni_poeni, :max_poeni, :vid_isprasuvanje)") void insertUsnaOcenka( @Param("id") UUID id, @Param("tema") String tema, @Param("osvoeni_poeni") Integer osvoeniPoeni, @Param("max_poeni") Integer maxPoeni, @Param("vid_isprasuvanje") String vidUsnoIsprasuvanje ); }}} = Безбеднст на ниво на база = Имаме имплементирано посебен корисник кој што не е главниот user: Исто така, користиме тип enum на ниво на база дополнително да се осигураме дека станува збор за вистинската категорија. {{{ CREATE TYPE payment_status AS ENUM ( 'KREIRANO', 'TX_SUBMITTED', 'ODOBRENO', 'ZAVRSENO', 'FAILED' ); CREATE TYPE notice_status AS ENUM ( 'PENDING', 'APPROVED', 'REJECTED' ); Потоа користиме CHECK за проверка: CREATE TABLE Plakjanje ( id UUID PRIMARY KEY DEFAULT gen_random_uuid (), status payment_status NOT NULL, tx_hash VARCHAR(100) UNIQUE, valuta VARCHAR(10) NOT NULL, plateno_Na TIMESTAMP, iznos DECIMAL(38, 18) NOT NULL, platenoOdRoditel_Id UUID NOT NULL, soopstenie_za_plakjanje_id UUID NOT NULL, created_at TIMESTAMP DEFAULT now(), UNIQUE ( platenoOdRoditel_Id, soopstenie_za_plakjanje_id ), CONSTRAINT chk_tx_hash_when_paid CHECK ( ( status = 'KREIRANO' AND tx_hash IS NULL ) OR ( status IN ( 'TX_SUBMITTED', 'ODOBRENO', 'ZAVRSENO', 'FAILED' ) AND tx_hash IS NOT NULL ) ), FOREIGN KEY (soopstenie_za_plakjanje_id) REFERENCES SoopstenieZa_Plakjanje (id), FOREIGN KEY (platenoOdRoditel_Id) REFERENCES Roditel (id) ); }}}