Implemented authorisation

This commit is contained in:
Andrey Terentev 2024-03-25 17:04:16 +07:00 committed by Andrey Terentev
parent 11ca677f65
commit b48b375e4e
22 changed files with 142 additions and 64 deletions

View File

@ -0,0 +1,39 @@
package ru.dragonestia.picker.api.exception;
import ru.dragonestia.picker.api.repository.response.ErrorResponse;
import java.util.Map;
public class AccountDoesNotExistsException extends ApiException {
public static final String ERROR_ID = "err.account.does_not_exists";
private final String accountId;
public AccountDoesNotExistsException(String accountId) {
this.accountId = accountId;
}
public AccountDoesNotExistsException(ErrorResponse errorResponse) {
this(errorResponse.details().get("accountId"));
}
public String getAccountId() {
return accountId;
}
@Override
public String getErrorId() {
return ERROR_ID;
}
@Override
public String getMessage() {
return "Account with id '" + accountId + "' does not exists";
}
@Override
public void appendDetailsToErrorResponse(Map<String, String> details) {
details.put("accountId", accountId);
}
}

View File

@ -25,6 +25,7 @@ public class ExceptionFactory {
factory.put(RoomAreFullException.ERROR_ID, RoomAreFullException::new); factory.put(RoomAreFullException.ERROR_ID, RoomAreFullException::new);
factory.put(RoomNotFoundException.ERROR_ID, RoomNotFoundException::new); factory.put(RoomNotFoundException.ERROR_ID, RoomNotFoundException::new);
factory.put(NotPersistedNodeException.ERROR_ID, NotPersistedNodeException::new); factory.put(NotPersistedNodeException.ERROR_ID, NotPersistedNodeException::new);
factory.put(AccountDoesNotExistsException.ERROR_ID, AccountDoesNotExistsException::new);
return factory; return factory;
} }

View File

@ -2,8 +2,10 @@ package ru.dragonestia.picker.api.impl.repository;
import org.jetbrains.annotations.ApiStatus.Internal; import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import ru.dragonestia.picker.api.exception.AccountDoesNotExistsException;
import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.RoomPickerClient;
import ru.dragonestia.picker.api.impl.util.RestTemplate; import ru.dragonestia.picker.api.impl.util.RestTemplate;
import ru.dragonestia.picker.api.impl.util.type.HttpMethod;
import ru.dragonestia.picker.api.model.account.ResponseAccount; import ru.dragonestia.picker.api.model.account.ResponseAccount;
import ru.dragonestia.picker.api.repository.AccountRepository; import ru.dragonestia.picker.api.repository.AccountRepository;
@ -20,6 +22,11 @@ public class AccountRepositoryImpl implements AccountRepository {
@Override @Override
public Optional<ResponseAccount> findAccountByUsername(@NotNull String username) { public Optional<ResponseAccount> findAccountByUsername(@NotNull String username) {
throw new UnsupportedOperationException("Not implemented"); try {
var response = rest.query("/accounts/" + username, HttpMethod.GET, ResponseAccount.class);
return Optional.of(response);
} catch (AccountDoesNotExistsException ex) {
return Optional.empty();
}
} }
} }

View File

@ -8,4 +8,4 @@ scrape_configs:
scrape_interval: 5s scrape_interval: 5s
metrics_path: '/actuator/prometheus' metrics_path: '/actuator/prometheus'
static_configs: static_configs:
- targets: [ 'host.docker.internal:8080' ] - targets: [ 'server:8080' ]

View File

@ -7,6 +7,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import ru.dragonestia.picker.cp.page.LoginPage; import ru.dragonestia.picker.cp.page.LoginPage;
import ru.dragonestia.picker.cp.service.AccountService; import ru.dragonestia.picker.cp.service.AccountService;
@ -39,16 +40,17 @@ public class SecurityConfig extends VaadinWebSecurity {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> { http.authorizeHttpRequests(auth -> {
auth.requestMatchers(AntPathRequestMatcher.antMatcher("/static/**")).permitAll();
});
http.formLogin(login -> {
login.successForwardUrl("/nodes");
}); });
http.userDetailsService(accountService); http.userDetailsService(accountService);
super.configure(http); super.configure(http);
http.formLogin(login -> {
login.successForwardUrl("/nodes");
login.defaultSuccessUrl("/nodes");
});
setLoginView(http, LoginPage.class); setLoginView(http, LoginPage.class);
} }
} }

View File

@ -6,6 +6,7 @@ import com.vaadin.flow.server.ErrorEvent;
import com.vaadin.flow.server.ErrorHandler; import com.vaadin.flow.server.ErrorHandler;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import ru.dragonestia.picker.api.exception.ApiException; import ru.dragonestia.picker.api.exception.ApiException;
import ru.dragonestia.picker.api.impl.exception.NotEnoughPermissions;
import ru.dragonestia.picker.cp.component.Notifications; import ru.dragonestia.picker.cp.component.Notifications;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
@ -34,6 +35,13 @@ public class ApplicationErrorHandler implements ErrorHandler {
return; return;
} }
if (errorEvent.getThrowable() instanceof NotEnoughPermissions) {
execute(() -> {
Notifications.error("Not enough permissions to this action");
});
return;
}
execute(() -> { execute(() -> {
Notifications.error("Internal server error"); Notifications.error("Internal server error");
}); });

View File

@ -19,7 +19,7 @@ public class Account implements IAccount, UserDetails {
public Account(ResponseAccount original, RoomPickerClient client) { public Account(ResponseAccount original, RoomPickerClient client) {
this.original = original; this.original = original;
this.client = client; this.client = client;
permissions = original.getPermissions().stream().map(Permission::new).collect(Collectors.toSet()); permissions = original.getPermissions().stream().map(permission -> new Permission("ROLE_" + permission)).collect(Collectors.toSet());
} }
public @NotNull RoomPickerClient getClient() { public @NotNull RoomPickerClient getClient() {

View File

@ -1,29 +0,0 @@
package ru.dragonestia.picker.cp.page;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.*;
import java.awt.*;
@Route(value = "/", layout = MainLayout.class)
public class HomePage extends VerticalLayout {
public HomePage() {
super();
var field = new TextField("Some field");
field.setRequired(true);
add(field);
var button = new Button("Click me", e -> {
Notification.show(field.isInvalid() + "");
});
add(button);
}
}

View File

@ -7,9 +7,11 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@Log4j2 @Log4j2
@AnonymousAllowed
@Route("/login") @Route("/login")
public class LoginPage extends VerticalLayout implements BeforeEnterObserver { public class LoginPage extends VerticalLayout implements BeforeEnterObserver {

View File

@ -16,13 +16,11 @@ import ru.dragonestia.picker.cp.annotation.ServerURL;
public class MainLayout extends AppLayout { public class MainLayout extends AppLayout {
private final RoomPickerClient client;
private final RoomPickerInfoResponse serverInfo; private final RoomPickerInfoResponse serverInfo;
private final String serverUrl; private final String serverUrl;
public MainLayout(RoomPickerClient client, @ServerURL String serverUrl) { public MainLayout(RoomPickerClient adminClient, @ServerURL String serverUrl) {
this.client = client; this.serverInfo = adminClient.getServerInfo();
this.serverInfo = client.getServerInfo();
this.serverUrl = serverUrl; this.serverUrl = serverUrl;
var toggle = new DrawerToggle(); var toggle = new DrawerToggle();
@ -47,7 +45,6 @@ public class MainLayout extends AppLayout {
nav.addItem(new SideNavItem("Search users", UserSearchPage.class, VaadinIcon.SEARCH.create())); nav.addItem(new SideNavItem("Search users", UserSearchPage.class, VaadinIcon.SEARCH.create()));
nav.addItem(new SideNavItem("Documentation", "https://github.com/ScarletRedMan/RoomPicker", VaadinIcon.BOOK.create())); nav.addItem(new SideNavItem("Documentation", "https://github.com/ScarletRedMan/RoomPicker", VaadinIcon.BOOK.create()));
nav.addItem(new SideNavItem("Swagger UI", serverUrl + "/api-docs-ui", VaadinIcon.CURLY_BRACKETS.create())); nav.addItem(new SideNavItem("Swagger UI", serverUrl + "/api-docs-ui", VaadinIcon.CURLY_BRACKETS.create()));
nav.addItem(new SideNavItem("Sign-out", HomePage.class, VaadinIcon.SIGN_OUT.create()));
return nav; return nav;
} }
} }

View File

@ -8,6 +8,7 @@ import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.RoomPickerClient;
@ -19,6 +20,7 @@ import ru.dragonestia.picker.cp.util.RouteParamsExtractor;
@Getter @Getter
@RequiredArgsConstructor @RequiredArgsConstructor
@PermitAll
@PageTitle("Rooms") @PageTitle("Rooms")
@Route(value = "/nodes/:nodeId", layout = MainLayout.class) @Route(value = "/nodes/:nodeId", layout = MainLayout.class)
public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver { public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver {

View File

@ -4,8 +4,8 @@ import com.vaadin.flow.component.html.Hr;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import lombok.Getter; import com.vaadin.flow.router.RouteAlias;
import lombok.extern.log4j.Log4j2; import jakarta.annotation.security.PermitAll;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import ru.dragonestia.picker.api.exception.ApiException; import ru.dragonestia.picker.api.exception.ApiException;
import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.RoomPickerClient;
@ -14,14 +14,13 @@ import ru.dragonestia.picker.cp.component.NavPath;
import ru.dragonestia.picker.cp.component.NodeList; import ru.dragonestia.picker.cp.component.NodeList;
import ru.dragonestia.picker.cp.component.RegisterNode; import ru.dragonestia.picker.cp.component.RegisterNode;
@Log4j2 @PermitAll
@Getter
@PageTitle("Nodes") @PageTitle("Nodes")
@RouteAlias(value = "/", layout = MainLayout.class)
@Route(value = "/nodes", layout = MainLayout.class) @Route(value = "/nodes", layout = MainLayout.class)
public class NodesPage extends VerticalLayout { public class NodesPage extends VerticalLayout {
private final NodeRepository nodeRepository; private final NodeRepository nodeRepository;
private final RegisterNode registerNode;
private final NodeList nodeList; private final NodeList nodeList;
public NodesPage(@Autowired RoomPickerClient client) { public NodesPage(@Autowired RoomPickerClient client) {
@ -29,7 +28,7 @@ public class NodesPage extends VerticalLayout {
this.nodeRepository = client.getNodeRepository(); this.nodeRepository = client.getNodeRepository();
add(NavPath.rootNodes()); add(NavPath.rootNodes());
add(registerNode = createRegisterNodeElement()); add(createRegisterNodeElement());
add(new Hr()); add(new Hr());
add(nodeList = createNodeListElement()); add(nodeList = createNodeListElement());
} }

View File

@ -13,6 +13,7 @@ import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.RoomPickerClient;
import ru.dragonestia.picker.api.model.node.INode; import ru.dragonestia.picker.api.model.node.INode;
@ -31,6 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
@PermitAll
@PageTitle("Room details") @PageTitle("Room details")
@Route(value = "/nodes/:nodeId/rooms/:roomId", layout = MainLayout.class) @Route(value = "/nodes/:nodeId/rooms/:roomId", layout = MainLayout.class)
public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserver { public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserver {
@ -40,7 +42,6 @@ public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserv
private INode node; private INode node;
private ResponseRoom room; private ResponseRoom room;
private AddUsers addUsers;
private UserList userList; private UserList userList;
private Button lockRoomButton; private Button lockRoomButton;
private VerticalLayout roomInfo; private VerticalLayout roomInfo;
@ -58,7 +59,7 @@ public class RoomDetailsPage extends VerticalLayout implements BeforeEnterObserv
add(new H2("Room details")); add(new H2("Room details"));
printRoomDetails(); printRoomDetails();
add(new Hr()); add(new Hr());
add(addUsers = new AddUsers(room, (users, ignoreLimitation) -> appendUsers(room, users, ignoreLimitation))); add(new AddUsers(room, (users, ignoreLimitation) -> appendUsers(room, users, ignoreLimitation)));
add(new Hr()); add(new Hr());
add(new H2("Users")); add(new H2("Users"));
add(userList = new UserList(room, client.getUserRepository())); add(userList = new UserList(room, client.getUserRepository()));

View File

@ -1,6 +1,5 @@
package ru.dragonestia.picker.cp.page; package ru.dragonestia.picker.cp.page;
import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.ColumnTextAlign; import com.vaadin.flow.component.grid.ColumnTextAlign;
@ -12,6 +11,7 @@ import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.RoomPickerClient;
import ru.dragonestia.picker.api.model.room.RoomDetails; import ru.dragonestia.picker.api.model.room.RoomDetails;
@ -21,11 +21,11 @@ import ru.dragonestia.picker.api.repository.query.user.FindRoomsLinkedWithUser;
import ru.dragonestia.picker.cp.component.RefreshableTable; import ru.dragonestia.picker.cp.component.RefreshableTable;
import ru.dragonestia.picker.cp.util.RouteParamsExtractor; import ru.dragonestia.picker.cp.util.RouteParamsExtractor;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@RequiredArgsConstructor @RequiredArgsConstructor
@PermitAll
@PageTitle("User details") @PageTitle("User details")
@Route(value = "/users/:userId", layout = MainLayout.class) @Route(value = "/users/:userId", layout = MainLayout.class)
public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserver, RefreshableTable { public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserver, RefreshableTable {
@ -34,7 +34,6 @@ public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserv
private final RouteParamsExtractor paramsExtractor; private final RouteParamsExtractor paramsExtractor;
private IUser user; private IUser user;
private Grid<ShortResponseRoom> gridRooms; private Grid<ShortResponseRoom> gridRooms;
private List<ShortResponseRoom> cachedRooms = new LinkedList<>();
@Override @Override
public void beforeEnter(BeforeEnterEvent event) { public void beforeEnter(BeforeEnterEvent event) {
@ -79,13 +78,9 @@ public class UserDetailsPage extends VerticalLayout implements BeforeEnterObserv
return grid; return grid;
} }
private Html createComponent(String defaultValue) {
return new Html("<span>" + defaultValue + "</span>");
}
@Override @Override
public void refresh() { public void refresh() {
cachedRooms = client.getUserRepository() List<ShortResponseRoom> cachedRooms = client.getUserRepository()
.findRoomsLinkedWithUser(FindRoomsLinkedWithUser.withAllDetails(user.getIdentifierObject())); .findRoomsLinkedWithUser(FindRoomsLinkedWithUser.withAllDetails(user.getIdentifierObject()));
gridRooms.setItems(cachedRooms); gridRooms.setItems(cachedRooms);
} }

View File

@ -13,6 +13,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import ru.dragonestia.picker.api.impl.RoomPickerClient; import ru.dragonestia.picker.api.impl.RoomPickerClient;
import ru.dragonestia.picker.api.model.user.IUser; import ru.dragonestia.picker.api.model.user.IUser;
@ -26,6 +27,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@PermitAll
@PageTitle("Search users") @PageTitle("Search users")
@Route(value = "/users", layout = MainLayout.class) @Route(value = "/users", layout = MainLayout.class)
public class UserSearchPage extends VerticalLayout implements RefreshableTable { public class UserSearchPage extends VerticalLayout implements RefreshableTable {

View File

@ -0,0 +1,24 @@
package ru.dragonestia.picker.cp.page.plug;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.ErrorParameter;
import com.vaadin.flow.router.HasErrorParameter;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.userdetails.User;
import ru.dragonestia.picker.api.impl.exception.NotEnoughPermissions;
public class NotEnoughPermissionsPlug extends ErrorPlug implements HasErrorParameter<NotEnoughPermissions> {
@Override
public int setErrorParameter(BeforeEnterEvent event, ErrorParameter<NotEnoughPermissions> parameter) {
return render(this);
}
public static int render(ErrorPlug plug) {
plug.add(new H1("Access denied"));
plug.add(new Paragraph("You do not have sufficient permissions to access this page"));
return HttpServletResponse.SC_FORBIDDEN;
}
}

View File

@ -17,3 +17,12 @@ services:
GF_SECURITY_ADMIN_PASSWORD: admin GF_SECURITY_ADMIN_PASSWORD: admin
volumes: volumes:
- "./appdata/grafana:/var/lib/grafana/" - "./appdata/grafana:/var/lib/grafana/"
server:
image: openjdk:17-oracle
ports:
- "8080:8080"
working_dir: "/app"
volumes:
- "./appdata/server:/app"
entrypoint: "java -jar -Dspring.profiles.active='test' server.jar"

View File

@ -1,10 +1,10 @@
package ru.dragonestia.picker.controller; package ru.dragonestia.picker.controller;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import ru.dragonestia.picker.api.model.account.ResponseAccount; import ru.dragonestia.picker.api.model.account.ResponseAccount;
import ru.dragonestia.picker.model.Account; import ru.dragonestia.picker.model.Account;
import ru.dragonestia.picker.service.AccountService; import ru.dragonestia.picker.service.AccountService;
@ -21,4 +21,13 @@ public class AccountsController {
var account = (Account) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); var account = (Account) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return account.toResponseObject(); return account.toResponseObject();
} }
@GetMapping("/{accountId}")
ResponseEntity<ResponseAccount> findAccount(@PathVariable String accountId) {
try {
return ResponseEntity.ok(accountService.loadUserByUsername(accountId).toResponseObject());
} catch (UsernameNotFoundException ex) {
return ResponseEntity.notFound().build();
}
}
} }

View File

@ -61,6 +61,11 @@ public class ExceptionHandlerController {
return create(400, ex); return create(400, ex);
} }
@ExceptionHandler(AccountDoesNotExistsException.class)
ResponseEntity<?> accountDoesNotExists(AccountDoesNotExistsException ex) {
return create(404, ex);
}
private ResponseEntity<ErrorResponse> create(int code, ApiException ex) { private ResponseEntity<ErrorResponse> create(int code, ApiException ex) {
var details = new HashMap<String, String>(); var details = new HashMap<String, String>();
ex.appendDetailsToErrorResponse(details); ex.appendDetailsToErrorResponse(details);

View File

@ -9,6 +9,6 @@ public enum Permission implements GrantedAuthority {
@Override @Override
public String getAuthority() { public String getAuthority() {
return name(); return "ROLE_" + name();
} }
} }

View File

@ -3,6 +3,7 @@ package ru.dragonestia.picker.service;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import ru.dragonestia.picker.model.Account; import ru.dragonestia.picker.model.Account;
import java.util.Collection; import java.util.Collection;
@ -17,4 +18,7 @@ public interface AccountService extends UserDetailsService {
@PreAuthorize("hasRole('ADMIN')") @PreAuthorize("hasRole('ADMIN')")
void removeAccount(@NotNull Account account); void removeAccount(@NotNull Account account);
@Override
Account loadUserByUsername(String username) throws UsernameNotFoundException;
} }

View File

@ -10,10 +10,11 @@ import ru.dragonestia.picker.model.Account;
import ru.dragonestia.picker.model.Permission; import ru.dragonestia.picker.model.Permission;
import ru.dragonestia.picker.service.AccountService; import ru.dragonestia.picker.service.AccountService;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -26,7 +27,7 @@ public class AccountServiceImpl implements AccountService {
@PostConstruct @PostConstruct
void init() { void init() {
var account = createNewAccount("admin", "qwerty123"); var account = createNewAccount("admin", "qwerty123");
account.setAuthorities(Set.of(Permission.ADMIN)); account.setAuthorities(Arrays.stream(Permission.values()).collect(Collectors.toSet()));
} }
public @NotNull Account createNewAccount(@NotNull String username, @NotNull String password) { public @NotNull Account createNewAccount(@NotNull String username, @NotNull String password) {