Konrad Neitzel 2c61ab5fc9 Add user authentication and management features
- Introduce user authentication with form-based login, including a default admin user.
- Implement UserEntity, UserRepository, and UserService for user management.
- Create RESTful endpoints for user listing and creation, restricted to admin role.
- Enhance OpenAPI specification to document new authentication and user management endpoints.
- Add frontend components for login and user management, including protected routes.
- Implement context and hooks for managing authentication state in the React application.
- Include unit tests for user service and authentication logic.
2026-02-22 11:28:04 +01:00

74 lines
2.4 KiB
Java

package de.neitzel.roleplay.fascade;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.inject.Inject;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import java.util.Map;
import java.util.stream.Collectors;
/**
* REST resource for auth-related endpoints: current user info and logout.
* Path is relative to {@code quarkus.rest.path} (/api/v1), so full paths are /api/v1/auth/me and /api/v1/auth/logout.
*/
@Path("auth")
@Produces(MediaType.APPLICATION_JSON)
public class AuthResource {
private static final String DEFAULT_COOKIE_NAME = "quarkus-credential";
private final SecurityIdentity securityIdentity;
private final String sessionCookieName;
@Inject
public AuthResource(
final SecurityIdentity securityIdentity,
@ConfigProperty(name = "quarkus.http.auth.form.cookie-name", defaultValue = DEFAULT_COOKIE_NAME)
final String sessionCookieName) {
this.securityIdentity = securityIdentity;
this.sessionCookieName = sessionCookieName;
}
/**
* Returns the current user's username and roles. Used by the frontend to check login state.
* Returns 401 when not authenticated (handled by Quarkus permission policy).
*/
@GET
@Path("me")
public Map<String, Object> me() {
if (securityIdentity.isAnonymous()) {
throw new ForbiddenException("Not authenticated");
}
return Map.of(
"username", securityIdentity.getPrincipal().getName(),
"roles", securityIdentity.getRoles().stream().collect(Collectors.toList()));
}
/**
* Logs out the current user by clearing the session cookie.
* Returns 204 No Content. Requires authenticated user.
*/
@POST
@Path("logout")
@Produces(MediaType.TEXT_PLAIN)
public Response logout() {
if (securityIdentity.isAnonymous()) {
throw new ForbiddenException("Not authenticated");
}
NewCookie clearCookie = new NewCookie.Builder(sessionCookieName)
.value("")
.path("/")
.maxAge(0)
.build();
return Response.noContent().cookie(clearCookie).build();
}
}