Skip to content

feat: AuthService och AuthController för login och register#204

Merged
lindaeskilsson merged 10 commits into
mainfrom
feat/AuthService-AuthController
Apr 15, 2026
Merged

feat: AuthService och AuthController för login och register#204
lindaeskilsson merged 10 commits into
mainfrom
feat/AuthService-AuthController

Conversation

@lindaeskilsson

@lindaeskilsson lindaeskilsson commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Implementerar autentiseringsflödet med login och registrering, kopplat till det befintliga JWT- och Spring Security-upplägget.

Ändringar
AuthService.java, affärslogik för autentisering:

  • login() autentiserar via AuthenticationManager och returnerar JWT
  • register() skapar ny användare med hashat lösenord och returnerar JWT
  • Admin-registrering är blockerad, nya användare får rollen OWNER
  • Duplicate email ger tydligt felmeddelande

AuthController.java — REST-endpoints:

  • POST /api/auth/login → returnerar 200 OK med JWT
  • POST /api/auth/register → returnerar 201 Created med JWT
  • Båda endpoints använder @Valid för input-validering
  • Öppna endpoints (ingen JWT krävs), redan konfigurerade som permitAll() i SecurityConfig

GlobalExceptionHandler.java - lagt till handler för BadCredentialsException som returnerar 401 Unauthorized vid fel lösenord

Säkerhet

Lösenord loggas aldrig
Lösenord hashas med BCrypt
JWT genereras via befintlig JwtService

Closes #198
Closes #199

Summary by CodeRabbit

  • New Features

    • Added user authentication: login and registration endpoints with token-based access and automatic role assignment.
  • Bug Fixes

    • Clearer authentication failure feedback with 401 responses and localized error message.
    • Business-rule errors now return 422 with specific error details.
  • Chores

    • Minor cleanup of internal service comments.

@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@lindaeskilsson has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 40 minutes and 25 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 40 minutes and 25 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d0901807-d0e7-4f27-baf3-a8ca2e2e8b0b

📥 Commits

Reviewing files that changed from the base of the PR and between 4dcbcdd and 73c7449.

📒 Files selected for processing (2)
  • src/test/java/org/example/vet1177/controller/UserControllerTest.java
  • src/test/java/org/example/vet1177/integration/vet/VetIntegrationTest.java
📝 Walkthrough

Walkthrough

Adds authentication feature: new AuthController (login/register), new AuthService (login/register with AuthenticationManager, PasswordEncoder, JwtService, UserRepository), a BadCredentialsException handler in GlobalExceptionHandler, and removed two commented TODOs in UserService.

Changes

Cohort / File(s) Summary
Exception Handling
src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java
Added @ExceptionHandler(BadCredentialsException.class) returning 401/"Felaktigt email eller lösenord"; changed BusinessRuleException handler to return 422 with the exception message.
Authentication Controller
src/main/java/org/example/vet1177/security/AuthController.java
New @RestController with POST /api/auth/login (200) and POST /api/auth/register (201); delegates to AuthService, uses @Valid @RequestBody``.
Authentication Service
src/main/java/org/example/vet1177/security/AuthService.java
New @Service implementing login(AuthRequest) (authenticate via AuthenticationManager, generate JWT) and register(RegisterRequest) (validate role/email, encode password, save user, generate JWT, translate DB constraint to BusinessRuleException).
Minor Cleanup
src/main/java/org/example/vet1177/services/UserService.java
Removed two commented TODOs referencing Spring Security and ADMIN check; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant AuthController
    participant AuthService
    participant AuthenticationManager
    participant JwtService
    participant UserRepository

    Client->>AuthController: POST /api/auth/login (email,password)
    AuthController->>AuthService: login(AuthRequest)
    AuthService->>AuthenticationManager: authenticate(UsernamePasswordAuthenticationToken)
    AuthenticationManager-->>AuthService: Authentication (User principal)
    AuthService->>JwtService: generateToken(user)
    JwtService-->>AuthService: JWT
    AuthService-->>AuthController: AuthResponse (token,user)
    AuthController-->>Client: 200 OK
Loading
sequenceDiagram
    actor Client
    participant AuthController
    participant AuthService
    participant UserRepository
    participant PasswordEncoder
    participant JwtService

    Client->>AuthController: POST /api/auth/register (name,email,password,role)
    AuthController->>AuthService: register(RegisterRequest)
    AuthService->>UserRepository: findByEmail(email)
    alt email exists
        UserRepository-->>AuthService: existing User
        AuthService-->>AuthController: throw BusinessRuleException("Email används redan")
        AuthController-->>Client: 422 Unprocessable Entity
    else email unique
        UserRepository-->>AuthService: null
        AuthService->>PasswordEncoder: encode(password)
        PasswordEncoder-->>AuthService: encoded password
        AuthService->>UserRepository: save(new User)
        UserRepository-->>AuthService: saved User
        AuthService->>JwtService: generateToken(user)
        JwtService-->>AuthService: JWT
        AuthService-->>AuthController: AuthResponse (token,user)
        AuthController-->>Client: 201 Created
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

säkerhet

Suggested reviewers

  • johanbriger
  • annikaholmqvist94

Poem

🐰 I hopped a token from code to sun,
I hid passwords where bunnies run,
Login, register — doors now neat,
Bad creds caught, no bitter treat.
Hooray! A secure hop — swift and fun 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding AuthService and AuthController for login and register functionality.
Linked Issues check ✅ Passed All requirements from #198 and #199 are implemented: AuthService with login/register handling JWT, exception handling for bad credentials, AuthController endpoints, and proper error messages.
Out of Scope Changes check ✅ Passed All changes directly support authentication flow requirements. The removal of TODO comments in UserService is a minor cleanup aligned with implementing the security features.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/AuthService-AuthController

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/main/java/org/example/vet1177/security/AuthService.java (1)

49-69: Small DRY refactor opportunity for AuthResponse creation.

new AuthResponse(...) is duplicated in both flows; extracting a private mapper improves maintainability.

♻️ Optional refactor
- return new AuthResponse(token, user.getId(), user.getName(), user.getEmail(), user.getRole());
+ return toAuthResponse(token, user);
...
- return new AuthResponse(token, user.getId(), user.getName(), user.getEmail(), user.getRole());
+ return toAuthResponse(token, user);
+
+private AuthResponse toAuthResponse(String token, User user) {
+    return new AuthResponse(token, user.getId(), user.getName(), user.getEmail(), user.getRole());
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/security/AuthService.java` around lines 49
- 69, Extract the duplicated AuthResponse construction into a single private
helper (e.g., private AuthResponse mapToAuthResponse(User user, String token) or
createAuthResponse) and replace both places that call new AuthResponse(...) (see
the return in register and the other AuthResponse return elsewhere) to call this
helper; ensure the helper returns new AuthResponse(token, user.getId(),
user.getName(), user.getEmail(), user.getRole()) so behavior remains identical
and update imports/logging if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/example/vet1177/security/AuthService.java`:
- Around line 53-56: AuthService throws BusinessRuleException with a specific
message ("Email används redan") but GlobalExceptionHandler currently returns a
fixed "Business rule violation" message, so the specific text never reaches
clients; update the BusinessRuleException handler in GlobalExceptionHandler (the
method that handles BusinessRuleException) to return the exception's message
(e.g., exception.getMessage()) or include it in the response body instead of the
fixed string, ensuring BusinessRuleException instances thrown from AuthService
(and elsewhere) propagate their specific messages to clients.
- Around line 53-66: AuthService.register() currently uses a TOCTOU check via
userRepository.findByEmail(...) then userRepository.save(...), which can race
and surface an unhandled DataIntegrityViolationException; remove the redundant
findByEmail check and wrap the userRepository.save(user) (and subsequent
jwtService.generateToken(user) if needed) in a try-catch that catches
org.springframework.dao.DataIntegrityViolationException and translates it into
the existing BusinessRuleException("Email används redan"); follow the pattern
used in UserService.create() to ensure constraint violations are handled
gracefully while preserving passwordEncoder.encode(...) and token generation.

---

Nitpick comments:
In `@src/main/java/org/example/vet1177/security/AuthService.java`:
- Around line 49-69: Extract the duplicated AuthResponse construction into a
single private helper (e.g., private AuthResponse mapToAuthResponse(User user,
String token) or createAuthResponse) and replace both places that call new
AuthResponse(...) (see the return in register and the other AuthResponse return
elsewhere) to call this helper; ensure the helper returns new
AuthResponse(token, user.getId(), user.getName(), user.getEmail(),
user.getRole()) so behavior remains identical and update imports/logging if
needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce445890-4fd7-436a-94fa-74b4ad8eac44

📥 Commits

Reviewing files that changed from the base of the PR and between 8deee0c and 793d5b6.

📒 Files selected for processing (4)
  • src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java
  • src/main/java/org/example/vet1177/security/AuthController.java
  • src/main/java/org/example/vet1177/security/AuthService.java
  • src/main/java/org/example/vet1177/services/UserService.java
💤 Files with no reviewable changes (1)
  • src/main/java/org/example/vet1177/services/UserService.java

Comment thread src/main/java/org/example/vet1177/security/AuthService.java Outdated
Comment thread src/main/java/org/example/vet1177/security/AuthService.java Outdated
request.name(),
request.email(),
passwordEncoder.encode(request.password()),
Role.OWNER

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bra jobbat med AuthService och AuthController login-flödet ser najs ut !

i register():

User user = new User(
request.name(),
request.email(),
passwordEncoder.encode(request.password()),
Role.OWNER // hårdkodat
);

Här är rollen hårdkodad till OWNER, men RegisterRequest har ett role-fält som frontend skickar med. Just nu ignoreras det fältet helt det kan bli förvirrande
Vi behöver bestämma en av dessa två vägar:

Alt 1: Bara OWNER kan registrera sig
Ta bort role-fältet från RegisterRequest helt?Då är det tydligt att register alltid skapar en OWNER. VET och ADMIN skapas av admin via andra endpoints.

Alt 2: OWNER och VET kan registrera sig
Använd request.role() istället för Role.OWNER, men en validering innan:
if (request.role() == Role.ADMIN) {
throw new BusinessRuleException("Admin-konton kan inte skapas via registrering");
}

Har vi tänkt alternativ 1?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jag tror alternativ 1 är det bästa alternativet! En VET och ADMIN bör enbart kunna skapas av en admin via POST /api/users, känns väl rimligast i en sån här applikation? Att vanliga användare som registrerar sig via register() får alltid rollen OWNER :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Håller med ovan, endast admin kan skapa en VET och en Admin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Skapa AuthController med login och register-endpoints Skapa AuthService med login och register

3 participants