fix logout

This commit is contained in:
Eduard Tihomirov 2024-10-24 11:54:21 +03:00
parent f44ef36459
commit ae6b1f19fe
8 changed files with 61 additions and 43 deletions

View file

@ -25,9 +25,7 @@ public class LogoutSuccessHandler
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {
String url = esiaAuthService.logout(request, response);
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write(url);
response.getWriter().flush();
response.sendRedirect(url);
CsrfToken csrfToken = this.csrfTokenRepository.generateToken(request);
this.csrfTokenRepository.saveToken(csrfToken, request, response);
}

View file

@ -24,6 +24,7 @@ import ru.micord.ervu.security.webbpm.jwt.JwtMatcher;
import ru.micord.ervu.security.webbpm.jwt.UnauthorizedEntryPoint;
import ru.micord.ervu.security.webbpm.jwt.filter.JwtAuthenticationFilter;
import ru.micord.ervu.security.webbpm.jwt.helper.SecurityHelper;
import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService;
import static ru.micord.ervu.security.SecurityConstants.ESIA_LOGOUT;
@ -97,9 +98,10 @@ public class SecurityConfig {
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(SecurityHelper securityHelper,
AuthenticationManager manager) {
AuthenticationManager manager,
JwtTokenService jwtTokenService) {
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(
new JwtMatcher("/**", PERMIT_ALL), entryPoint(), securityHelper);
new JwtMatcher("/**", PERMIT_ALL), entryPoint(), securityHelper, jwtTokenService);
jwtAuthenticationFilter.setAuthenticationManager(manager);
return jwtAuthenticationFilter;
}

View file

@ -22,6 +22,7 @@ import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContext;
import ru.micord.ervu.kafka.model.Document;
@ -43,7 +44,6 @@ import ru.micord.ervu.security.webbpm.jwt.JwtAuthentication;
import ru.micord.ervu.security.webbpm.jwt.helper.SecurityHelper;
import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService;
import ru.micord.ervu.security.webbpm.jwt.model.Token;
import ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil;
/**
* @author Eduard Tihomirov
@ -201,17 +201,13 @@ public class EsiaAuthService {
}
String accessToken = tokenResponse.getAccess_token();
String refreshToken = tokenResponse.getRefresh_token();
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(accessToken.indexOf('.') + 1, accessToken.lastIndexOf('.')));
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString, EsiaAccessToken.class);
EsiaAccessToken esiaAccessToken = personalDataService.readToken(accessToken);
String prnOid = esiaAccessToken.getSbj_id();
Long expiresIn = tokenResponse.getExpires_in();
TokensStore.addAccessToken(prnOid, accessToken, expiresIn);
TokensStore.addRefreshToken(prnOid, refreshToken, expiresIn);
String ervuId = getErvuId(accessToken);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId);
Response ervuIdResponse = getErvuIdResponse(accessToken);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuIdResponse.getErvuId());
int expiry = tokenResponse.getExpires_in().intValue();
Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry);
response.addCookie(accessCookie);
@ -224,6 +220,12 @@ public class EsiaAuthService {
SecurityContextHolder.setContext(context);
Cookie authMarkerCookie = securityHelper.createAuthMarkerCookie("true", expiry);
response.addCookie(authMarkerCookie);
if (ervuIdResponse.getErrorData() != null) {
return new ResponseEntity<>(
"Доступ запрещен. " + ervuIdResponse.getErrorData().getName(),
HttpStatus.FORBIDDEN
);
}
return ResponseEntity.ok("Authentication successful");
}
catch (Exception e) {
@ -279,18 +281,13 @@ public class EsiaAuthService {
}
String accessToken = tokenResponse.getAccess_token();
String newRefreshToken = tokenResponse.getRefresh_token();
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(accessToken.indexOf('.') + 1, accessToken.lastIndexOf('.')));
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString, EsiaAccessToken.class);
EsiaAccessToken esiaAccessToken = personalDataService.readToken(accessToken);
String prnOid = esiaAccessToken.getSbj_id();
Long expiresIn = tokenResponse.getExpires_in();
TokensStore.addAccessToken(prnOid, accessToken, expiresIn);
TokensStore.addRefreshToken(prnOid, newRefreshToken, expiresIn);
String ervuId = getErvuId(accessToken);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuId);
Response ervuIdResponse = getErvuIdResponse(accessToken);
Token token = jwtTokenService.createAccessToken(esiaAccessToken.getSbj_id(), expiresIn, ervuIdResponse.getErvuId());
int expiry = tokenResponse.getExpires_in().intValue();
Cookie accessCookie = securityHelper.createAccessCookie(token.getValue(), expiry);
response.addCookie(accessCookie);
@ -360,22 +357,14 @@ public class EsiaAuthService {
}
}
public String getErvuId(String accessToken) {
public Response getErvuIdResponse(String accessToken) {
try {
PersonModel personModel = personalDataService.getPersonModel(accessToken);
Person person = copyToPerson(personModel);
String kafkaResponse = replyingKafkaService.sendMessageAndGetReply(requestTopic,
requestReplyTopic, objectMapper.writeValueAsString(person)
);
Response response = objectMapper.readValue(kafkaResponse, Response.class);
if (response.getErrorData() != null) {
throw new RuntimeException(
"Error code = " + response.getErrorData().getCode() + ", error name = "
+ response.getErrorData().getName());
}
else {
return response.getErvuId();
}
return objectMapper.readValue(kafkaResponse, Response.class);
}
catch (Exception e) {
throw new RuntimeException(e);

View file

@ -31,11 +31,7 @@ public class EsiaPersonalDataService implements PersonalDataService {
@Override
public PersonModel getPersonModel(String accessToken) {
try {
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(accessToken.indexOf('.') + 1, accessToken.lastIndexOf('.')));
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString, EsiaAccessToken.class);
EsiaAccessToken esiaAccessToken = readToken(accessToken);
String prnsId = esiaAccessToken.getSbj_id();
PersonModel personModel = getPersonData(prnsId, accessToken);
personModel.setPassportModel(
@ -88,4 +84,23 @@ public class EsiaPersonalDataService implements PersonalDataService {
throw new RuntimeException(e);
}
}
@Override
public EsiaAccessToken readToken(String accessToken) {
try {
byte[] decodedBytes = Base64.getDecoder()
.decode(
accessToken.substring(accessToken.indexOf('.') + 1, accessToken.lastIndexOf('.'))
.replace('-', '+')
.replace('_', '/'));
String decodedString = new String(decodedBytes);
EsiaAccessToken esiaAccessToken = objectMapper.readValue(decodedString,
EsiaAccessToken.class
);
return esiaAccessToken;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View file

@ -1,5 +1,6 @@
package ru.micord.ervu.security.esia.service;
import ru.micord.ervu.security.esia.model.EsiaAccessToken;
import ru.micord.ervu.security.esia.model.PersonModel;
/**
@ -8,4 +9,5 @@ import ru.micord.ervu.security.esia.model.PersonModel;
public interface PersonalDataService {
PersonModel getPersonModel(String accessToken);
EsiaAccessToken readToken(String accessToken);
}

View file

@ -18,6 +18,8 @@ import org.springframework.security.web.authentication.AbstractAuthenticationPro
import org.springframework.security.web.util.matcher.RequestMatcher;
import ru.micord.ervu.security.webbpm.jwt.JwtAuthentication;
import ru.micord.ervu.security.webbpm.jwt.helper.SecurityHelper;
import ru.micord.ervu.security.webbpm.jwt.model.Token;
import ru.micord.ervu.security.webbpm.jwt.service.JwtTokenService;
import static ru.micord.ervu.security.webbpm.jwt.util.SecurityUtil.extractAuthToken;
@ -33,25 +35,36 @@ public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFil
private final SecurityHelper securityHelper;
private final JwtTokenService jwtTokenService;
public JwtAuthenticationFilter(RequestMatcher requestMatcher,
AuthenticationEntryPoint entryPoint,
SecurityHelper securityHelper) {
SecurityHelper securityHelper,
JwtTokenService jwtTokenService) {
super(requestMatcher);
this.entryPoint = entryPoint;
this.securityHelper = securityHelper;
this.jwtTokenService = jwtTokenService;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws AuthenticationException {
String token = extractAuthToken(httpServletRequest);
String tokenStr = extractAuthToken(httpServletRequest);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
authentication = new JwtAuthentication(null, null, token);
authentication = new JwtAuthentication(null, null, tokenStr);
}
try {
authentication = getAuthenticationManager().authenticate(authentication);
if (!httpServletRequest.getRequestURI().endsWith("esia/logout")) {
Token token = jwtTokenService.getToken(tokenStr);
String[] ids = token.getUserAccountId().split(":");
if (ids.length != 2) {
throw new CredentialsExpiredException("Invalid token. User has no ervuId");
}
}
}
catch (CredentialsExpiredException e) {
securityHelper.clearAccessCookies(httpServletResponse);

View file

@ -3,3 +3,4 @@
<a routerLink="/mydata" class="data">Мои данные</a>
<button ngbDropdownItem class="exit" (click)="logout()">Выйти</button>
</div>
<button class="exit" *ngIf="!getIsAuth()" (click)="logout()">Выйти</button>

View file

@ -28,9 +28,7 @@ export class LogOutComponent implements OnInit{
}
public logout(): void {
this.httpClient.get<string>("esia/logout").toPromise().then(url => {
window.open(url, "_self");
})
this.httpClient.get<any>("esia/logout").toPromise();
}
public getUserFullname(): string {