server-side auth handling and managing endpoints
This commit is contained in:
parent
a4c29fafeb
commit
b128628f49
3 changed files with 76 additions and 13 deletions
|
@ -2,61 +2,113 @@ package me.imsonmia.epqapi.controller;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.aspectj.internal.lang.annotation.ajcDeclareAnnotation;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
import io.micrometer.common.lang.Nullable;
|
import io.micrometer.common.lang.Nullable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Setter;
|
||||||
|
import me.imsonmia.epqapi.model.User;
|
||||||
import me.imsonmia.epqapi.repository.UserRepository;
|
import me.imsonmia.epqapi.repository.UserRepository;
|
||||||
|
@Controller
|
||||||
@RequestMapping("/api/v1")
|
@RequestMapping("/api/v1")
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
@Autowired
|
||||||
private UserRepository userRepository;
|
private UserRepository userRepository;
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AuthData
|
* AuthData
|
||||||
*/
|
*/
|
||||||
|
@Data
|
||||||
public class AuthData {
|
public class AuthData {
|
||||||
|
|
||||||
private boolean success;
|
private boolean success;
|
||||||
private boolean hasProfile;
|
private boolean hasProfile;
|
||||||
private boolean exists;
|
private boolean exists;
|
||||||
private String authMessage;
|
private String authMessage;
|
||||||
private long authResponseTimestampMillis;
|
private long authResponseTimestampMillis;
|
||||||
|
|
||||||
public AuthData(boolean success, boolean hasProfile, @Nullable String authMessage) {
|
public AuthData(boolean success, boolean hasProfile, boolean exists, @Nullable String authMessage) {
|
||||||
this.success = success;
|
this.success = success;
|
||||||
this.hasProfile = hasProfile;
|
this.hasProfile = hasProfile;
|
||||||
|
this.exists = exists;
|
||||||
this.authMessage = authMessage == null ? "" : authMessage;
|
this.authMessage = authMessage == null ? "" : authMessage;
|
||||||
this.authResponseTimestampMillis = new Date().getTime();
|
this.authResponseTimestampMillis = new Date().getTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class AuthRequestData {
|
public static class AuthRequestData {
|
||||||
private String userName;
|
private String userName;
|
||||||
private String userPasswordHash;
|
private String userPasswordHash;
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
public String getUserPasswordHash() {
|
||||||
|
return userPasswordHash;
|
||||||
|
}
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
public void setUserPasswordHash(String userPasswordHash) {
|
||||||
|
this.userPasswordHash = userPasswordHash;
|
||||||
|
}
|
||||||
|
public AuthRequestData() {
|
||||||
|
|
||||||
|
}
|
||||||
public AuthRequestData(String userName, String userPasswordHash) {
|
public AuthRequestData(String userName, String userPasswordHash) {
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
this.userPasswordHash = userPasswordHash;
|
this.userPasswordHash = userPasswordHash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Data
|
||||||
|
public static class RegisterRequestData {
|
||||||
|
@Setter
|
||||||
|
private String userName;
|
||||||
|
@Setter
|
||||||
|
private String newUserPassword;
|
||||||
|
public RegisterRequestData() {}
|
||||||
|
public RegisterRequestData(String userName, String newUserPassword) {
|
||||||
|
this.userName = userName;
|
||||||
|
this.newUserPassword = newUserPassword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/register")
|
||||||
|
public ResponseEntity<AuthData> authRegister(@RequestBody RegisterRequestData registerRequestData) {
|
||||||
|
if (userRepository.existsByUserName(registerRequestData.userName)) {
|
||||||
|
return new ResponseEntity<>(new AuthData(false, true, true, "Login failed. Username already exists."), null,
|
||||||
|
200);
|
||||||
|
}
|
||||||
|
User newUser = new User(UUID.randomUUID().toString(), registerRequestData.userName, new Date(), new Date(),
|
||||||
|
registerRequestData.newUserPassword);
|
||||||
|
userRepository.save(newUser);
|
||||||
|
return new ResponseEntity<AuthData>(new AuthData(true, true, true, "Login successful. Used registration endpoint."),
|
||||||
|
null, 200);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authentication HTTPS endpoint used instead of client-side verification which
|
* Authentication HTTPS endpoint used instead of client-side verification which
|
||||||
* is unsafe
|
* is unsafe
|
||||||
*/
|
*/
|
||||||
@PostMapping("/auth")
|
@PostMapping(value = "/auth",
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<AuthData> authLogin(@RequestBody AuthRequestData authRequestData) {
|
public ResponseEntity<AuthData> authLogin(@RequestBody AuthRequestData authRequestData) {
|
||||||
if (!userRepository.existsByUserName(authRequestData.userName)) {
|
if (!userRepository.existsByUserName(authRequestData.userName)) {
|
||||||
|
|
||||||
logger.info("Invalid login since user doesn't exist");
|
logger.info("Invalid login since user doesn't exist");
|
||||||
return new ResponseEntity<AuthData>(new AuthData(
|
return new ResponseEntity<AuthData>(new AuthData(
|
||||||
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
"Login invalid: User doesn't exist in database."),
|
"Login invalid: User doesn't exist in database."),
|
||||||
|
@ -64,10 +116,16 @@ public class AuthController {
|
||||||
200);
|
200);
|
||||||
}
|
}
|
||||||
String pwdHash = userRepository.findByUserName(authRequestData.userName).get().getPasswordHash();
|
String pwdHash = userRepository.findByUserName(authRequestData.userName).get().getPasswordHash();
|
||||||
if (pwdHash != authRequestData.userPasswordHash) {
|
// NOTE Cannot use straight == comparison. Must use equals function @ 22:17 2024-04-01
|
||||||
return new ResponseEntity<>(new AuthData(false, true, "Login invalid: Password incorrect."), null, 200);
|
if (!pwdHash.equals(authRequestData.getUserPasswordHash())) {
|
||||||
|
return new ResponseEntity<>(new AuthData(
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
"Login invalid: Password incorrect."
|
||||||
|
), null, 200);
|
||||||
} else {
|
} else {
|
||||||
return new ResponseEntity<>(new AuthData(true, true, "Authentication success"), null, 200);
|
return new ResponseEntity<>(new AuthData(true, true, true, "Authentication success"), null, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package me.imsonmia.epqapi.controller;
|
package me.imsonmia.epqapi.controller;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.misc.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
import org.springframework.messaging.handler.annotation.SendTo;
|
import org.springframework.messaging.handler.annotation.SendTo;
|
||||||
|
@ -13,6 +14,7 @@ import me.imsonmia.epqapi.repository.MessageRepository;
|
||||||
public class MessageController {
|
public class MessageController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private MessageRepository repository;
|
private MessageRepository repository;
|
||||||
|
|
||||||
@MessageMapping("/chat")
|
@MessageMapping("/chat")
|
||||||
@SendTo("/sub/chat")
|
@SendTo("/sub/chat")
|
||||||
public Message messageHandler(Message message) throws Exception {
|
public Message messageHandler(Message message) throws Exception {
|
||||||
|
@ -21,9 +23,9 @@ public class MessageController {
|
||||||
// Forward message to subscribers of Stomp endpoint
|
// Forward message to subscribers of Stomp endpoint
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @GetMapping("/msg/{id}")
|
// @GetMapping("/msg/{id}")
|
||||||
// public ChatMessage getMessageById(@PathVariable(value = "id") Long id) {
|
// public ChatMessage getMessageById(@PathVariable(value = "id") Long id) {
|
||||||
// return chatMessageRepository.findById(id).get();
|
// return chatMessageRepository.findById(id).get();
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ public class User {
|
||||||
Long id;
|
Long id;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
String userId;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
String userName;
|
String userName;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@ -34,8 +37,8 @@ public class User {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public User(Long id, String userName, Date dateJoined, Date lastSeen, String passwordHash) {
|
public User(String userId, String userName, Date dateJoined, Date lastSeen, String passwordHash) {
|
||||||
this.id = id;
|
this.userId = userId;
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
this.dateJoined = dateJoined;
|
this.dateJoined = dateJoined;
|
||||||
this.lastSeen = lastSeen;
|
this.lastSeen = lastSeen;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue