SUPPORT-8601, SUPPORT-8602, SUPPORT-8613, SUPPORT-8599

This commit is contained in:
Eduard Tihomirov 2024-10-18 11:41:42 +03:00
parent e8c64daa28
commit 8120afbcf4
8 changed files with 124 additions and 18 deletions

View file

@ -28,6 +28,9 @@ public class S3Service {
public ResponseEntity<Resource> getFile(String fileUrl) {
try {
if (fileUrl == null || fileUrl.isEmpty()) {
return ResponseEntity.noContent().build();
}
AmazonS3URI uri = new AmazonS3URI(fileUrl);
S3Object s3Object = outClient.getObject(uri.getBucket(), uri.getKey());
InputStreamResource resource = new InputStreamResource(s3Object.getObjectContent());

View file

@ -3,6 +3,7 @@ package ru.micord.ervu.security.esia.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import ru.micord.ervu.security.esia.model.OrgInfoModel;
import ru.micord.ervu.security.esia.service.EsiaAuthService;
import ru.micord.ervu.security.esia.service.EsiaDataService;
@ -30,7 +31,7 @@ public class EsiaController {
}
@RequestMapping(value = "/esia/auth", params = "code", method = RequestMethod.GET)
public boolean esiaAuth(@RequestParam("code") String code, HttpServletRequest request, HttpServletResponse response) {
public ResponseEntity<?> esiaAuth(@RequestParam("code") String code, HttpServletRequest request, HttpServletResponse response) {
return esiaAuthService.getEsiaTokensByCode(code, request, response);
}

View file

@ -1,6 +1,7 @@
package ru.micord.ervu.security.esia.service;
import java.io.UnsupportedEncodingException;
import java.lang.invoke.MethodHandles;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
@ -21,6 +22,10 @@ import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import ervu.service.okopf.OkopfService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.util.StringUtils;
import ru.micord.ervu.security.esia.config.EsiaConfig;
@ -50,6 +55,8 @@ import ru.micord.ervu.security.webbpm.jwt.model.Token;
@Service
public class EsiaAuthService {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Value("${cookie-path:#{null}}")
private String path;
@ -154,7 +161,7 @@ public class EsiaAuthService {
return uriBuilder.toString();
}
public boolean getEsiaTokensByCode(String esiaAuthCode, HttpServletRequest request, HttpServletResponse response) {
public ResponseEntity<?> getEsiaTokensByCode(String esiaAuthCode, HttpServletRequest request, HttpServletResponse response) {
try {
String clientId = esiaConfig.getClientId();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss xx");
@ -205,8 +212,14 @@ public class EsiaAuthService {
}
String accessToken = tokenResponse.getAccess_token();
boolean hasRole = ulDataService.checkRole(accessToken);
EsiaAccessToken esiaAccessToken = ulDataService.readToken(accessToken);
String prnOid = esiaAccessToken.getSbj_id();
if (!hasRole) {
throw new RuntimeException("The user does not have the required role");
LOGGER.error("The user with id = " + prnOid + " does not have the required role");
return new ResponseEntity<>(
"Доступ запрещен. Пользователь должен быть включен в группу \"Сотрудник, ответственный за военно-учетную работу\" в ЕСИА",
HttpStatus.FORBIDDEN
);
}
String cookiePath = null;
if (path != null) {
@ -225,8 +238,6 @@ public class EsiaAuthService {
cookieRefresh.setHttpOnly(true);
cookieRefresh.setPath(cookiePath);
response.addCookie(cookieRefresh);
EsiaAccessToken esiaAccessToken = ulDataService.readToken(accessToken);
String ervuId = getErvuId(accessToken, esiaAccessToken.getSbj_id());
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), tokenResponse.getExpires_in(), ervuId);
Cookie authToken = new Cookie("auth_token", token.getValue());
@ -245,7 +256,7 @@ public class EsiaAuthService {
isAuth.setMaxAge(tokenResponse.getExpires_in().intValue());
isAuth.setPath("/");
response.addCookie(isAuth);
return true;
return ResponseEntity.ok("Authentication successful");
}
catch (Exception e) {
throw new RuntimeException(e);
@ -442,7 +453,9 @@ public class EsiaAuthService {
private OrgInfo copyToOrgInfo(OrganizationModel organizationModel, EmployeeModel employeeModel, EmployeeModel chiefModel ) {
OrgInfo orgInfo = new OrgInfo();
orgInfo.setChiefInfo(copyToEmployee(chiefModel));
if (chiefModel != null) {
orgInfo.setChiefInfo(copyToEmployee(chiefModel));
}
orgInfo.setSenderInfo(copyToEmployee(employeeModel));
orgInfo.setBrhs(
Arrays.stream(organizationModel.getBrhs()).map(brhsModel -> {

View file

@ -44,10 +44,12 @@ public class EsiaDataService {
}
} );
}
orgInfoModel.chiefFullname =
chiefEmployeeModel.getPerson().getLastName() + " " + chiefEmployeeModel.getPerson()
.getFirstName() + " " + chiefEmployeeModel.getPerson().getMiddleName();
orgInfoModel.chiefPosition = chiefEmployeeModel.getPosition();
if (chiefEmployeeModel != null) {
orgInfoModel.chiefFullname =
chiefEmployeeModel.getPerson().getLastName() + " " + chiefEmployeeModel.getPerson()
.getFirstName() + " " + chiefEmployeeModel.getPerson().getMiddleName();
orgInfoModel.chiefPosition = chiefEmployeeModel.getPosition();
}
orgInfoModel.ogrn = organizationModel.getOgrn();
orgInfoModel.kpp = organizationModel.getKpp();
orgInfoModel.inn = organizationModel.getInn();

View file

@ -1,6 +1,8 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef} from "@angular/core";
import {AbstractButton, NotNull} from "@webbpm/base-package";
import {AbstractButton, MessagesService, NotNull, ObjectRef} from "@webbpm/base-package";
import {HttpClient} from "@angular/common/http";
import {InMemoryStaticGrid} from "../grid/InMemoryStaticGrid";
import {Subscription} from "rxjs";
/**
* @author: Eduard Tihomirov
@ -13,10 +15,19 @@ import {HttpClient} from "@angular/common/http";
})
export class ErvuDownloadFileButton extends AbstractButton {
private httpClient: HttpClient;
private messageService: MessagesService;
private gridLoadedSubscription: Subscription;
@ObjectRef()
@NotNull()
public grid: InMemoryStaticGrid;
@NotNull()
public fileName: string;
@NotNull()
public noFileMessage: string;
constructor(el: ElementRef, cd: ChangeDetectorRef) {
super(el, cd);
}
@ -24,6 +35,26 @@ export class ErvuDownloadFileButton extends AbstractButton {
initialize() {
super.initialize();
this.httpClient = this.injector.get(HttpClient);
this.messageService = this.injector.get(MessagesService);
if (this.grid.isInitialized() && this.grid.getRowDataSize() > 0) {
this.setEnabled(true);
this.setVisible(true);
}
this.gridLoadedSubscription = this.grid.gridLoaded.subscribe(() => {
if (this.grid.getRowDataSize() > 0) {
this.setEnabled(true);
this.setVisible(true);
}
else {
this.setEnabled(false);
this.setVisible(false);
}
});
}
ngOnDestroy() {
super.ngOnDestroy();
this.gridLoadedSubscription.unsubscribe();
}
public doClickActions(): Promise<any> {
@ -31,6 +62,9 @@ export class ErvuDownloadFileButton extends AbstractButton {
responseType: 'blob',
observe: 'response'
}).toPromise().then((response) => {
if (response.status == 204) {
this.messageService.info(this.noFileMessage)
}
const contentDisposition = response.headers.get('Content-Disposition');
const url = window.URL.createObjectURL(response.body);
const a = document.createElement('a');

View file

@ -0,0 +1,12 @@
class EsiaErrorDetail {
private static errors: { [code: string]: string } = {
'ESIA-007071': 'Запрос персональных данных по физическим лицам может быть выполнен только с указанием согласий',
'ESIA-007055': 'Вход в систему осуществляется с неподтвержденной учетной записью',
'ESIA-007036': 'Учетная запись заблокирована',
'ESIA-007008': 'Сервис авторизации в настоящее время не может выполнить запрос из-за большой нагрузки или технических работ на сервере',
};
static getDescription(code: string): string {
return this.errors[code] || 'Доступ запрещен. Обратитесь к системному администратору. Ошибка ' + code;
}
}

View file

@ -30,14 +30,31 @@ export abstract class AuthGuard implements CanActivate {
return true;
}
else if (error) {
let errorMessage = error + ', error description =' + errorDescription;
this.messageService.error(errorMessage)
let userErrorMessage = 'Произошла неизвестная ошибка. Обратитесь к системному администратору';
let errorCode = this.extractCode(errorDescription);
if (errorCode) {
userErrorMessage = EsiaErrorDetail.getDescription(errorCode);
}
let errorMessage = error + ', error description = ' + errorDescription;
this.messageService.error(userErrorMessage)
throw new Error(errorMessage);
}
else if (code) {
const params = new HttpParams().set('code', code);
this.httpClient.get<boolean>("esia/auth", {params: params}).toPromise().then(
() => window.open(url.origin + url.pathname, "_self"))
this.httpClient.get("esia/auth",
{params: params, responseType: 'text', observe: 'response'})
.toPromise()
.then(
(response) => {
if (response.status == 200) {
window.open(url.origin + url.pathname, "_self");
}
else {
let errorMessage = response.body;
this.messageService.error(errorMessage)
throw new Error(errorMessage)
}
})
.catch((reason) =>
console.error(reason)
);
@ -62,4 +79,10 @@ export abstract class AuthGuard implements CanActivate {
public getIsAuth(): string {
return this.cookieService.get('webbpm.ervu-lkrp-ul');
}
private extractCode(message: string): string | null {
const regex = /ESIA-\d{6}/;
const match = message.match(regex);
return match ? match[0] : null;
}
}

View file

@ -1286,16 +1286,34 @@
<simple>"Запросить выписку"</simple>
</value>
</entry>
<entry>
<key>disabled</key>
<value>
<simple>true</simple>
</value>
</entry>
<entry>
<key>fileName</key>
<value>
<simple>"Выписка"</simple>
<simple>"Выписка.xlsx"</simple>
</value>
</entry>
<entry>
<key>grid</key>
<value>
<simple>{"objectId":"bbaf33d7-0679-440b-a394-cb805ce80300","packageName":"ervu.component.grid","className":"InMemoryStaticGrid","type":"TS"}</simple>
</value>
</entry>
<entry>
<key>noFileMessage</key>
<value>
<simple>"Нет записей в выписке журнала взаимодействия"</simple>
</value>
</entry>
<entry>
<key>visible</key>
<value>
<simple>true</simple>
<simple>false</simple>
</value>
</entry>
</properties>