SUPPORT-8601, SUPPORT-8602, SUPPORT-8613, SUPPORT-8599
This commit is contained in:
parent
e8c64daa28
commit
8120afbcf4
8 changed files with 124 additions and 18 deletions
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 -> {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
12
frontend/src/ts/modules/security/EsiaErrorDetail.ts
Normal file
12
frontend/src/ts/modules/security/EsiaErrorDetail.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue