backend-api #6
@@ -1,14 +1,32 @@
 | 
				
			|||||||
package enseirb.myinpulse.api;
 | 
					package enseirb.myinpulse.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
					import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
				
			||||||
 | 
					import org.springframework.security.core.context.SecurityContextHolder;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.management.relation.RoleNotFoundException;
 | 
				
			||||||
 | 
					import java.security.Principal;
 | 
				
			||||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
					import org.springframework.web.bind.annotation.GetMapping;
 | 
				
			||||||
import org.springframework.web.bind.annotation.RestController;
 | 
					import org.springframework.web.bind.annotation.RestController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@SpringBootApplication
 | 
					@SpringBootApplication
 | 
				
			||||||
@RestController
 | 
					@RestController
 | 
				
			||||||
public class GetUserInfo {
 | 
					public class GetUserInfo {
 | 
				
			||||||
 | 
					    // TODO: understand how to get data
 | 
				
			||||||
 | 
					    @GetMapping("/getUserInfo")
 | 
				
			||||||
 | 
					    public Object user(Principal principal) {
 | 
				
			||||||
 | 
					        System.out.println("GetUserInfo + " + principal);
 | 
				
			||||||
 | 
					        System.out.println(SecurityContextHolder.getContext().getAuthentication());
 | 
				
			||||||
 | 
					        return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @CrossOrigin(methods = {RequestMethod.GET, RequestMethod.OPTIONS})
 | 
				
			||||||
    @GetMapping("/unauth/random")
 | 
					    @GetMapping("/unauth/random")
 | 
				
			||||||
    public boolean rand() {
 | 
					    public boolean rand(@RequestHeader("Authorization") String token) throws RoleNotFoundException {
 | 
				
			||||||
 | 
					        System.err.println(token);
 | 
				
			||||||
 | 
					        System.err.println("HELLO");
 | 
				
			||||||
        return Math.random() > 0.5;
 | 
					        return Math.random() > 0.5;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package enseirb.myinpulse.exceptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RoleNotFoudException extends RuntimeException {
 | 
				
			||||||
 | 
					    public RoleNotFoudException(String message) {
 | 
				
			||||||
 | 
					        super(message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package enseirb.myinpulse.exceptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class UserNotFoundException extends RuntimeException {
 | 
				
			||||||
 | 
					    public UserNotFoundException(String message) {
 | 
				
			||||||
 | 
					        super(message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Source: https://github.com/ChristianHuff-DEV/secure-spring-rest-api-using-keycloak/blob/main/src/main/java/io/betweendata/RestApi/security/oauth2/KeycloakJwtRolesConverter.java
 | 
				
			||||||
 | 
					 * edited by Pierre Tellier
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
package enseirb.myinpulse.security;
 | 
					package enseirb.myinpulse.security;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static java.util.stream.Collectors.toSet;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.springframework.core.convert.converter.Converter;
 | 
					import org.springframework.core.convert.converter.Converter;
 | 
				
			||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
					import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
				
			||||||
import org.springframework.security.core.GrantedAuthority;
 | 
					import org.springframework.security.core.GrantedAuthority;
 | 
				
			||||||
@@ -16,37 +18,43 @@ import java.util.Map;
 | 
				
			|||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
import java.util.stream.Stream;
 | 
					import java.util.stream.Stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
 | 
					import static java.util.stream.Collectors.toSet;
 | 
				
			||||||
    /** Prefix used for realm level roles. */
 | 
					 | 
				
			||||||
    public static final String PREFIX_REALM_ROLE = "ROLE_REALM_";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Prefix used in combination with the resource (client) name for resource level roles. */
 | 
					
 | 
				
			||||||
 | 
					public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Prefix used for realm level roles.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final String PREFIX_REALM_ROLE = "ROLE_REALM_";
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Prefix used in combination with the resource (client) name for resource level roles.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public static final String PREFIX_RESOURCE_ROLE = "ROLE_";
 | 
					    public static final String PREFIX_RESOURCE_ROLE = "ROLE_";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Name of the claim containing the realm level roles */
 | 
					    /**
 | 
				
			||||||
 | 
					     * Name of the claim containing the realm level roles
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private static final String CLAIM_REALM_ACCESS = "realm_access";
 | 
					    private static final String CLAIM_REALM_ACCESS = "realm_access";
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
    /** Name of the claim containing the resources (clients) the user has access to. */
 | 
					     * Name of the claim containing the resources (clients) the user has access to.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private static final String CLAIM_RESOURCE_ACCESS = "resource_access";
 | 
					    private static final String CLAIM_RESOURCE_ACCESS = "resource_access";
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
    /** Name of the claim containing roles. (Applicable to realm and resource level.) */
 | 
					     * Name of the claim containing roles. (Applicable to realm and resource level.)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private static final String CLAIM_ROLES = "roles";
 | 
					    private static final String CLAIM_ROLES = "roles";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public AbstractAuthenticationToken convert(Jwt source) {
 | 
					    public AbstractAuthenticationToken convert(Jwt source) {
 | 
				
			||||||
        return new JwtAuthenticationToken(
 | 
					        return new JwtAuthenticationToken(source, Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
 | 
				
			||||||
                source,
 | 
					                        .stream(), tokenRolesExtractor(source).stream())
 | 
				
			||||||
                Stream.concat(
 | 
					                .collect(toSet()));
 | 
				
			||||||
                                new JwtGrantedAuthoritiesConverter().convert(source).stream(),
 | 
					 | 
				
			||||||
                                TEMPORARNAME(source).stream())
 | 
					 | 
				
			||||||
                        .collect(toSet()));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Extracts the realm and resource level roles from a JWT token distinguishing between them
 | 
					     * Extracts the realm and resource level roles from a JWT token distinguishing between them using prefixes.
 | 
				
			||||||
     * using prefixes.
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public Collection<GrantedAuthority> TEMPORARNAME(Jwt jwt) {
 | 
					    public Collection<GrantedAuthority> tokenRolesExtractor(Jwt jwt) {
 | 
				
			||||||
        // Collection that will hold the extracted roles
 | 
					        // Collection that will hold the extracted roles
 | 
				
			||||||
        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
 | 
					        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,43 +69,33 @@ public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthent
 | 
				
			|||||||
            // Check if any roles are present
 | 
					            // Check if any roles are present
 | 
				
			||||||
            if (roles != null && !roles.isEmpty()) {
 | 
					            if (roles != null && !roles.isEmpty()) {
 | 
				
			||||||
                // Iterate of the roles and add them to the granted authorities
 | 
					                // Iterate of the roles and add them to the granted authorities
 | 
				
			||||||
                Collection<GrantedAuthority> realmRoles =
 | 
					                Collection<GrantedAuthority> realmRoles = roles.stream()
 | 
				
			||||||
                        roles.stream()
 | 
					                        // Prefix all realm roles with "ROLE_realm_"
 | 
				
			||||||
                                // Prefix all realm roles with "ROLE_realm_"
 | 
					                        .map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
 | 
				
			||||||
                                .map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
 | 
					                        .collect(Collectors.toList());
 | 
				
			||||||
                                .collect(Collectors.toList());
 | 
					 | 
				
			||||||
                grantedAuthorities.addAll(realmRoles);
 | 
					                grantedAuthorities.addAll(realmRoles);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Resource (client) roles
 | 
					        // Resource (client) roles
 | 
				
			||||||
        // A user might have access to multiple resources all containing their own roles. Therefore,
 | 
					        // A user might have access to multiple resources all containing their own roles. Therefore, it is a map of
 | 
				
			||||||
        // it is a map of
 | 
					 | 
				
			||||||
        // resource each possibly containing a "roles" property.
 | 
					        // resource each possibly containing a "roles" property.
 | 
				
			||||||
        Map<String, Map<String, Collection<String>>> resourceAccess =
 | 
					        Map<String, Map<String, Collection<String>>> resourceAccess = jwt.getClaim(CLAIM_RESOURCE_ACCESS);
 | 
				
			||||||
                jwt.getClaim(CLAIM_RESOURCE_ACCESS);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Check if resources are assigned
 | 
					        // Check if resources are assigned
 | 
				
			||||||
        if (resourceAccess != null && !resourceAccess.isEmpty()) {
 | 
					        if (resourceAccess != null && !resourceAccess.isEmpty()) {
 | 
				
			||||||
            // Iterate of all the resources
 | 
					            // Iterate of all the resources
 | 
				
			||||||
            resourceAccess.forEach(
 | 
					            resourceAccess.forEach((resource, resourceClaims) -> {
 | 
				
			||||||
                    (resource, resourceClaims) -> {
 | 
					                // Iterate of the "roles" claim inside the resource claims
 | 
				
			||||||
                        // Iterate of the "roles" claim inside the resource claims
 | 
					                resourceClaims.get(CLAIM_ROLES).forEach(
 | 
				
			||||||
                        resourceClaims
 | 
					                        // Add the role to the granted authority prefixed with ROLE_ and the name of the resource
 | 
				
			||||||
                                .get(CLAIM_ROLES)
 | 
					                        role -> grantedAuthorities.add(new SimpleGrantedAuthority(PREFIX_RESOURCE_ROLE + resource + "_" + role))
 | 
				
			||||||
                                .forEach(
 | 
					                );
 | 
				
			||||||
                                        // Add the role to the granted authority prefixed with ROLE_
 | 
					            });
 | 
				
			||||||
                                        // and the name of the resource
 | 
					 | 
				
			||||||
                                        role ->
 | 
					 | 
				
			||||||
                                                grantedAuthorities.add(
 | 
					 | 
				
			||||||
                                                        new SimpleGrantedAuthority(
 | 
					 | 
				
			||||||
                                                                PREFIX_RESOURCE_ROLE
 | 
					 | 
				
			||||||
                                                                        + resource
 | 
					 | 
				
			||||||
                                                                        + "_"
 | 
					 | 
				
			||||||
                                                                        + role)));
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return grantedAuthorities;
 | 
					        return grantedAuthorities;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					package enseirb.myinpulse.utils.keycloak;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.springframework.http.MediaType.APPLICATION_JSON;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import enseirb.myinpulse.exceptions.UserNotFoundException;
 | 
				
			||||||
 | 
					import enseirb.myinpulse.utils.keycloak.datatypes.RoleRepresentation;
 | 
				
			||||||
 | 
					import enseirb.myinpulse.utils.keycloak.datatypes.UserRepresentation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.web.client.RestClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.management.relation.RoleNotFoundException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class KeycloakApi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static final String keycloakUrl;
 | 
				
			||||||
 | 
					    static final String realmName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static {
 | 
				
			||||||
 | 
					        if (System.getenv("VITE_KEYCLOAK_URL") == null) {
 | 
				
			||||||
 | 
					            System.exit(-1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        keycloakUrl = System.getenv("VITE_KEYCLOAK_URL");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static {
 | 
				
			||||||
 | 
					        if (System.getenv("VITE_KEYCLOAK_REALM") == null) {
 | 
				
			||||||
 | 
					            System.exit(-1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        realmName = System.getenv("VITE_KEYCLOAK_REALM");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Uses Keycloak API to retrieve a role representation of a role by its name
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param roleName name of the role
 | 
				
			||||||
 | 
					     * @param bearer authorization header used by the client to authenticate to keycloak
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static RoleRepresentation getRoleRepresentationByName(String roleName, String bearer)
 | 
				
			||||||
 | 
					            throws RoleNotFoundException {
 | 
				
			||||||
 | 
					        RoleRepresentation[] response =
 | 
				
			||||||
 | 
					                RestClient.builder()
 | 
				
			||||||
 | 
					                        .baseUrl(keycloakUrl)
 | 
				
			||||||
 | 
					                        .defaultHeader("Authorization", bearer)
 | 
				
			||||||
 | 
					                        .build()
 | 
				
			||||||
 | 
					                        .get()
 | 
				
			||||||
 | 
					                        .uri("/admin/realms/{realmName}/roles/{roleName}", realmName, roleName)
 | 
				
			||||||
 | 
					                        .retrieve()
 | 
				
			||||||
 | 
					                        .body(RoleRepresentation[].class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (response == null || response.length == 0) {
 | 
				
			||||||
 | 
					            throw new RoleNotFoundException("Role not found");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return response[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Use keycloak API to to retreive a userID via his name or email.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param username username or mail of the user
 | 
				
			||||||
 | 
					     * @param bearer bearer of the user, allowing access to database
 | 
				
			||||||
 | 
					     * @return the userid, as a String
 | 
				
			||||||
 | 
					     * @throws UserNotFoundException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static String getUserIdByName(String username, String bearer)
 | 
				
			||||||
 | 
					            throws UserNotFoundException {
 | 
				
			||||||
 | 
					        UserRepresentation[] response =
 | 
				
			||||||
 | 
					                RestClient.builder()
 | 
				
			||||||
 | 
					                        .baseUrl(keycloakUrl)
 | 
				
			||||||
 | 
					                        .defaultHeader("Authorization", bearer)
 | 
				
			||||||
 | 
					                        .build()
 | 
				
			||||||
 | 
					                        .get()
 | 
				
			||||||
 | 
					                        .uri(
 | 
				
			||||||
 | 
					                                "/admin/realms/{realmName}/users?username={username}",
 | 
				
			||||||
 | 
					                                realmName,
 | 
				
			||||||
 | 
					                                username)
 | 
				
			||||||
 | 
					                        .retrieve()
 | 
				
			||||||
 | 
					                        .body(UserRepresentation[].class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (response == null || response.length == 0) {
 | 
				
			||||||
 | 
					            throw new UserNotFoundException("User not found");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return response[0].id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * TODO: check for error
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * <p>Set a keycloak role to a keycloak user.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * <p>Usual roles should be `MyINPulse-admin` and `MyINPulse-entrepreneur`
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param username
 | 
				
			||||||
 | 
					     * @param roleName
 | 
				
			||||||
 | 
					     * @param bearer
 | 
				
			||||||
 | 
					     * @throws RoleNotFoundException
 | 
				
			||||||
 | 
					     * @throws UserNotFoundException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static void setRoleToUser(String username, String roleName, String bearer)
 | 
				
			||||||
 | 
					            throws RoleNotFoundException, UserNotFoundException {
 | 
				
			||||||
 | 
					        RoleRepresentation roleRepresentation = getRoleRepresentationByName(roleName, bearer);
 | 
				
			||||||
 | 
					        String userId = getUserIdByName(username, bearer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        RestClient.builder()
 | 
				
			||||||
 | 
					                .baseUrl(keycloakUrl)
 | 
				
			||||||
 | 
					                .defaultHeader("Authorization", bearer)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					                .post()
 | 
				
			||||||
 | 
					                .uri(
 | 
				
			||||||
 | 
					                        "/admin/realms/${realmName}/users/${userId}/role-mappings/realm",
 | 
				
			||||||
 | 
					                        realmName,
 | 
				
			||||||
 | 
					                        userId)
 | 
				
			||||||
 | 
					                .body(roleRepresentation)
 | 
				
			||||||
 | 
					                .contentType(APPLICATION_JSON)
 | 
				
			||||||
 | 
					                .retrieve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete a user from Keycloak database. TODO: check the bearer permission.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param username
 | 
				
			||||||
 | 
					     * @param bearer
 | 
				
			||||||
 | 
					     * @throws UserNotFoundException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static void deleteUser(String username, String bearer) throws UserNotFoundException {
 | 
				
			||||||
 | 
					        String userId = getUserIdByName(username, bearer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        RestClient.builder()
 | 
				
			||||||
 | 
					                .baseUrl(keycloakUrl)
 | 
				
			||||||
 | 
					                .defaultHeader("Authorization", bearer)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					                .delete()
 | 
				
			||||||
 | 
					                .uri("/admin/realms/${realmName}/users/${userId}", realmName, userId)
 | 
				
			||||||
 | 
					                .retrieve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package enseirb.myinpulse.utils.keycloak.datatypes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RoleRepresentation {
 | 
				
			||||||
 | 
					    public String id;
 | 
				
			||||||
 | 
					    public String name;
 | 
				
			||||||
 | 
					    public String description;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package enseirb.myinpulse.utils.keycloak.datatypes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class UserRepresentation {
 | 
				
			||||||
 | 
					    public String id;
 | 
				
			||||||
 | 
					    public String name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,7 +14,8 @@ axiosInstance.interceptors.response.use(
 | 
				
			|||||||
    async (error) => {
 | 
					    async (error) => {
 | 
				
			||||||
        const originalRequest = error.config;
 | 
					        const originalRequest = error.config;
 | 
				
			||||||
        if (
 | 
					        if (
 | 
				
			||||||
            error.response.status === 401 &&
 | 
					            ((error.response && error.response.status === 401) ||
 | 
				
			||||||
 | 
					                error.code == "ERR_NETWORK") &&
 | 
				
			||||||
            !originalRequest._retry &&
 | 
					            !originalRequest._retry &&
 | 
				
			||||||
            store.authenticated
 | 
					            store.authenticated
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,9 @@
 | 
				
			|||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { store } from "../main.ts";
 | 
					import { store } from "../main.ts";
 | 
				
			||||||
import { callApi } from "@/services/api.ts";
 | 
					import { callApi } from "@/services/api.ts";
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CustomRequest = ref("");
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
@@ -55,6 +58,14 @@ import { callApi } from "@/services/api.ts";
 | 
				
			|||||||
                <td>res</td>
 | 
					                <td>res</td>
 | 
				
			||||||
                <td id="3"></td>
 | 
					                <td id="3"></td>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <input v-model="CustomRequest" placeholder="edit me" />
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <button @click="callApi(CustomRequest)">call</button>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
        </tbody>
 | 
					        </tbody>
 | 
				
			||||||
    </table>
 | 
					    </table>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user