diff --git a/pom.xml b/pom.xml
index bc6325e..b0dccd4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,15 @@
hibernate-validator
6.0.16.Final
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
diff --git a/src/main/java/swg/controller/AuthController.java b/src/main/java/swg/controller/AuthController.java
new file mode 100644
index 0000000..3a4166e
--- /dev/null
+++ b/src/main/java/swg/controller/AuthController.java
@@ -0,0 +1,59 @@
+package swg.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.web.bind.annotation.*;
+import swg.payload.request.LoginRequest;
+import swg.payload.response.JwtResponse;
+import swg.repository.UasUserDao;
+import swg.security.jwt.JwtUtils;
+import swg.service.UserDetailsImpl;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@CrossOrigin(origins = "*", maxAge = 3600)
+@RestController
+@RequestMapping("/api/auth")
+public class AuthController {
+ @Autowired
+ AuthenticationManager authenticationManager;
+
+ @Autowired
+ UasUserDao userRepository;
+
+ @Autowired
+ PasswordEncoder encoder;
+
+ @Autowired
+ JwtUtils jwtUtils;
+
+ @PostMapping("/login")
+ public ResponseEntity> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
+ UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
+
+ Authentication authentication = authenticationManager.authenticate(authReq);
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String jwt = jwtUtils.generateJwtToken(authentication);
+
+ UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
+ List roles = userDetails.getAuthorities().stream()
+ .map(item-> item.getAuthority())
+ .collect(Collectors.toList());
+
+ return ResponseEntity.ok(new JwtResponse(
+ jwt,
+ userDetails.getId(),
+ userDetails.getUsername(),
+ userDetails.getEmail(),
+ roles
+ ));
+ }
+}
diff --git a/src/main/java/swg/controller/ResourceTypeController.java b/src/main/java/swg/controller/ResourceTypeController.java
index c3ce1d7..5b7ae0d 100644
--- a/src/main/java/swg/controller/ResourceTypeController.java
+++ b/src/main/java/swg/controller/ResourceTypeController.java
@@ -1,6 +1,7 @@
package swg.controller;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -11,7 +12,7 @@ import swg.service.ResourceTypeService;
import java.util.List;
-@CrossOrigin
+@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/resource")
public class ResourceTypeController {
@@ -20,6 +21,7 @@ public class ResourceTypeController {
ClockService clockService;
@RequestMapping(value = "/historical/all", method = RequestMethod.GET)
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
public List getAllResources() {
return resourceTypeService.getAllResources();
}
diff --git a/src/main/java/swg/entity/UasUser.java b/src/main/java/swg/entity/UasUser.java
new file mode 100644
index 0000000..6389e80
--- /dev/null
+++ b/src/main/java/swg/entity/UasUser.java
@@ -0,0 +1,84 @@
+package swg.entity;
+
+import javax.persistence.*;
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+@Entity
+@Table(name = "UAS_USERS",
+ uniqueConstraints = {
+ @UniqueConstraint(columnNames = "USERNAME"),
+ @UniqueConstraint(columnNames = "EMAIL")
+ })
+public class UasUser {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @NotBlank
+ @Size(max = 20)
+ private String username;
+
+ @NotBlank
+ @Size(max = 50)
+ @Email
+ private String email;
+
+ @NotBlank
+ @Size(max = 120)
+ private String password;
+
+ @NotBlank
+ @Enumerated(EnumType.STRING)
+ private UserRole userrole;
+
+ public UasUser() {
+ }
+
+ public UasUser(String username, String email, String password) {
+ this.username = username;
+ this.email = email;
+ this.password = password;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public UserRole getUserRole() {
+ return userrole;
+ }
+
+ public void setUserRole(UserRole userRole) {
+ this.userrole = userRole;
+ }
+}
diff --git a/src/main/java/swg/entity/UserRole.java b/src/main/java/swg/entity/UserRole.java
new file mode 100644
index 0000000..33014c9
--- /dev/null
+++ b/src/main/java/swg/entity/UserRole.java
@@ -0,0 +1,7 @@
+package swg.entity;
+
+public enum UserRole {
+ ROLE_USER,
+ ROLE_MODERATOR,
+ ROLE_ADMIN
+}
diff --git a/src/main/java/swg/payload/request/LoginRequest.java b/src/main/java/swg/payload/request/LoginRequest.java
new file mode 100644
index 0000000..dd41715
--- /dev/null
+++ b/src/main/java/swg/payload/request/LoginRequest.java
@@ -0,0 +1,27 @@
+package swg.payload.request;
+
+import javax.validation.constraints.NotBlank;
+
+public class LoginRequest {
+ @NotBlank
+ private String username;
+
+ @NotBlank
+ private String password;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/swg/payload/response/JwtResponse.java b/src/main/java/swg/payload/response/JwtResponse.java
new file mode 100644
index 0000000..c4ccbfc
--- /dev/null
+++ b/src/main/java/swg/payload/response/JwtResponse.java
@@ -0,0 +1,64 @@
+package swg.payload.response;
+
+import java.util.List;
+
+public class JwtResponse {
+ private String token;
+ private String type = "Bearer";
+ private Long id;
+ private String username;
+ private String email;
+ private List roles;
+
+ public JwtResponse(String accessToken, Long id, String username, String email, List roles) {
+ this.token = accessToken;
+ this.id = id;
+ this.username = username;
+ this.email = email;
+ this.roles = roles;
+ }
+
+ public String getAccessToken() {
+ return token;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.token = accessToken;
+ }
+
+ public String getTokenType() {
+ return type;
+ }
+
+ public void setTokenType(String tokenType) {
+ this.type = tokenType;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/swg/payload/response/MessageResponse.java b/src/main/java/swg/payload/response/MessageResponse.java
new file mode 100644
index 0000000..b51e311
--- /dev/null
+++ b/src/main/java/swg/payload/response/MessageResponse.java
@@ -0,0 +1,17 @@
+package swg.payload.response;
+
+public class MessageResponse {
+ private String message;
+
+ public MessageResponse(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/swg/dao/AccountDao.java b/src/main/java/swg/repository/AccountDao.java
similarity index 92%
rename from src/main/java/swg/dao/AccountDao.java
rename to src/main/java/swg/repository/AccountDao.java
index b467919..fb9f68f 100644
--- a/src/main/java/swg/dao/AccountDao.java
+++ b/src/main/java/swg/repository/AccountDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/swg/dao/CityObjectDao.java b/src/main/java/swg/repository/CityObjectDao.java
similarity index 88%
rename from src/main/java/swg/dao/CityObjectDao.java
rename to src/main/java/swg/repository/CityObjectDao.java
index 86053ba..668d56f 100644
--- a/src/main/java/swg/dao/CityObjectDao.java
+++ b/src/main/java/swg/repository/CityObjectDao.java
@@ -1,12 +1,9 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import swg.entity.CityObject;
-import swg.entity.PropertyList;
-
-import java.util.List;
@Repository
public interface CityObjectDao extends JpaRepository {
diff --git a/src/main/java/swg/dao/ClockDao.java b/src/main/java/swg/repository/ClockDao.java
similarity index 90%
rename from src/main/java/swg/dao/ClockDao.java
rename to src/main/java/swg/repository/ClockDao.java
index 562a0c7..d09e53e 100644
--- a/src/main/java/swg/dao/ClockDao.java
+++ b/src/main/java/swg/repository/ClockDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/swg/dao/MarketAuctionDao.java b/src/main/java/swg/repository/MarketAuctionDao.java
similarity index 92%
rename from src/main/java/swg/dao/MarketAuctionDao.java
rename to src/main/java/swg/repository/MarketAuctionDao.java
index 7a88834..d94fd74 100644
--- a/src/main/java/swg/dao/MarketAuctionDao.java
+++ b/src/main/java/swg/repository/MarketAuctionDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/swg/dao/ObjectsDao.java b/src/main/java/swg/repository/ObjectsDao.java
similarity index 96%
rename from src/main/java/swg/dao/ObjectsDao.java
rename to src/main/java/swg/repository/ObjectsDao.java
index 33fab41..132bcf5 100644
--- a/src/main/java/swg/dao/ObjectsDao.java
+++ b/src/main/java/swg/repository/ObjectsDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
diff --git a/src/main/java/swg/dao/PlayerDao.java b/src/main/java/swg/repository/PlayerDao.java
similarity index 93%
rename from src/main/java/swg/dao/PlayerDao.java
rename to src/main/java/swg/repository/PlayerDao.java
index 8668f78..9b0c375 100644
--- a/src/main/java/swg/dao/PlayerDao.java
+++ b/src/main/java/swg/repository/PlayerDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/swg/dao/PlayerObjectDao.java b/src/main/java/swg/repository/PlayerObjectDao.java
similarity index 92%
rename from src/main/java/swg/dao/PlayerObjectDao.java
rename to src/main/java/swg/repository/PlayerObjectDao.java
index 2390ec4..f53d5aa 100644
--- a/src/main/java/swg/dao/PlayerObjectDao.java
+++ b/src/main/java/swg/repository/PlayerObjectDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/swg/dao/PropertyListDao.java b/src/main/java/swg/repository/PropertyListDao.java
similarity index 81%
rename from src/main/java/swg/dao/PropertyListDao.java
rename to src/main/java/swg/repository/PropertyListDao.java
index 8abc93f..a377959 100644
--- a/src/main/java/swg/dao/PropertyListDao.java
+++ b/src/main/java/swg/repository/PropertyListDao.java
@@ -1,10 +1,8 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
-import swg.entity.Player;
import swg.entity.PropertyList;
-import swg.entity.ResourceType;
import java.util.List;
diff --git a/src/main/java/swg/dao/ResourceTypeDao.java b/src/main/java/swg/repository/ResourceTypeDao.java
similarity index 95%
rename from src/main/java/swg/dao/ResourceTypeDao.java
rename to src/main/java/swg/repository/ResourceTypeDao.java
index a8220d2..8a87e92 100644
--- a/src/main/java/swg/dao/ResourceTypeDao.java
+++ b/src/main/java/swg/repository/ResourceTypeDao.java
@@ -1,4 +1,4 @@
-package swg.dao;
+package swg.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
diff --git a/src/main/java/swg/repository/UasUserDao.java b/src/main/java/swg/repository/UasUserDao.java
new file mode 100644
index 0000000..e8b4660
--- /dev/null
+++ b/src/main/java/swg/repository/UasUserDao.java
@@ -0,0 +1,14 @@
+package swg.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import swg.entity.UasUser;
+
+import java.util.Optional;
+
+@Repository
+public interface UasUserDao extends JpaRepository {
+ Optional findByUsername(String username);
+ Boolean existsByUsername(String username);
+ Boolean existsByEmail(String email);
+}
\ No newline at end of file
diff --git a/src/main/java/swg/security/WebSecurityConfig.java b/src/main/java/swg/security/WebSecurityConfig.java
new file mode 100644
index 0000000..1a446e7
--- /dev/null
+++ b/src/main/java/swg/security/WebSecurityConfig.java
@@ -0,0 +1,66 @@
+package swg.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+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.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import swg.security.jwt.AuthEntryPointJwt;
+import swg.security.jwt.AuthTokenFilter;
+import swg.service.UserDetailsServiceImpl;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(
+ // securedEnabled = true,
+ // jsr250Enabled = true,
+ prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+ @Autowired
+ UserDetailsServiceImpl userDetailsService;
+
+ @Autowired
+ private AuthEntryPointJwt unauthorizedHandler;
+
+ @Bean
+ public AuthTokenFilter authenticationJwtTokenFilter() {
+ return new AuthTokenFilter();
+ }
+
+ @Override
+ public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
+ authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
+ }
+
+ @Bean
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.cors().and().csrf().disable()
+ .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+ .authorizeRequests()
+ .antMatchers("/api/auth/**").permitAll()
+// .antMatchers("/api/test/**").permitAll()
+ .anyRequest().authenticated();
+
+ http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/swg/security/jwt/AuthEntryPointJwt.java b/src/main/java/swg/security/jwt/AuthEntryPointJwt.java
new file mode 100644
index 0000000..1bd3bbb
--- /dev/null
+++ b/src/main/java/swg/security/jwt/AuthEntryPointJwt.java
@@ -0,0 +1,23 @@
+package swg.security.jwt;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class AuthEntryPointJwt implements AuthenticationEntryPoint {
+ private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);
+
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
+ logger.error("Unauthorized error: {}", authException.getMessage());
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
+ }
+}
diff --git a/src/main/java/swg/security/jwt/AuthTokenFilter.java b/src/main/java/swg/security/jwt/AuthTokenFilter.java
new file mode 100644
index 0000000..2f3105d
--- /dev/null
+++ b/src/main/java/swg/security/jwt/AuthTokenFilter.java
@@ -0,0 +1,62 @@
+package swg.security.jwt;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+import swg.service.UserDetailsServiceImpl;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class AuthTokenFilter extends OncePerRequestFilter {
+ @Autowired
+ private JwtUtils jwtUtils;
+
+ @Autowired
+ private UserDetailsServiceImpl userDetailsService;
+
+ private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+ try {
+ String jwt = parseJwt(request);
+ if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
+ String username = jwtUtils.getUserNameFromJwtToken(jwt);
+
+ UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+ UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
+ userDetails,
+ null,
+ userDetails.getAuthorities()
+ );
+ authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ }
+ catch (Exception e) {
+ logger.error("Cannot set user authentication: {}", e.getMessage());
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+ private String parseJwt(HttpServletRequest request) {
+ String headerAuth = request.getHeader("Authorization");
+
+ if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
+ return headerAuth.substring(7, headerAuth.length());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/swg/security/jwt/JwtUtils.java b/src/main/java/swg/security/jwt/JwtUtils.java
new file mode 100644
index 0000000..caeda46
--- /dev/null
+++ b/src/main/java/swg/security/jwt/JwtUtils.java
@@ -0,0 +1,55 @@
+package swg.security.jwt;
+
+import io.jsonwebtoken.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+import swg.service.UserDetailsImpl;
+
+import java.util.Date;
+
+@Component
+public class JwtUtils {
+ private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
+
+ @Value("${swg.app.jwtSecret}")
+ private String jwtSecret;
+
+ @Value("${swg.app.jwtExpirationMs}")
+ private int jwtExpirationMs;
+
+ public String generateJwtToken(Authentication authentication) {
+ UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
+
+ return Jwts.builder()
+ .setSubject((userPrincipal.getUsername()))
+ .setIssuedAt(new Date())
+ .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
+ .signWith(SignatureAlgorithm.HS256, jwtSecret)
+ .compact();
+ }
+
+ public String getUserNameFromJwtToken(String token) {
+ return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
+ }
+
+ public boolean validateJwtToken(String authToken) {
+ try {
+ Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
+ return true;
+ } catch (SignatureException e) {
+ logger.error("Invalid JWT signature: {}", e.getMessage());
+ } catch (MalformedJwtException e) {
+ logger.error("Invalid JWT token: {}", e.getMessage());
+ } catch (ExpiredJwtException e) {
+ logger.error("JWT token is expired: {}", e.getMessage());
+ } catch (UnsupportedJwtException e) {
+ logger.error("JWT token is unsupported: {}", e.getMessage());
+ } catch (IllegalArgumentException e) {
+ logger.error("JWT claims string is empty: {}", e.getMessage());
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/swg/service/AccountService.java b/src/main/java/swg/service/AccountService.java
index 0373f39..5c0c94f 100644
--- a/src/main/java/swg/service/AccountService.java
+++ b/src/main/java/swg/service/AccountService.java
@@ -2,7 +2,7 @@ package swg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.AccountDao;
+import swg.repository.AccountDao;
import swg.entity.Account;
import java.util.List;
diff --git a/src/main/java/swg/service/CityObjectService.java b/src/main/java/swg/service/CityObjectService.java
index 1bca73e..4fab158 100644
--- a/src/main/java/swg/service/CityObjectService.java
+++ b/src/main/java/swg/service/CityObjectService.java
@@ -1,10 +1,8 @@
package swg.service;
-import org.hibernate.mapping.Property;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.CityObjectDao;
-import swg.dao.PropertyListDao;
+import swg.repository.CityObjectDao;
import swg.entity.CityObject;
import swg.entity.PropertyList;
diff --git a/src/main/java/swg/service/ClockService.java b/src/main/java/swg/service/ClockService.java
index 531258d..0305023 100644
--- a/src/main/java/swg/service/ClockService.java
+++ b/src/main/java/swg/service/ClockService.java
@@ -2,7 +2,7 @@ package swg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.ClockDao;
+import swg.repository.ClockDao;
import swg.entity.Clock;
import java.util.List;
diff --git a/src/main/java/swg/service/MarketAuctionService.java b/src/main/java/swg/service/MarketAuctionService.java
index 5f94871..45c5d70 100644
--- a/src/main/java/swg/service/MarketAuctionService.java
+++ b/src/main/java/swg/service/MarketAuctionService.java
@@ -2,7 +2,7 @@ package swg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.MarketAuctionDao;
+import swg.repository.MarketAuctionDao;
import swg.entity.MarketAuction;
import java.util.List;
diff --git a/src/main/java/swg/service/PlayerService.java b/src/main/java/swg/service/PlayerService.java
index be22826..0f5a953 100644
--- a/src/main/java/swg/service/PlayerService.java
+++ b/src/main/java/swg/service/PlayerService.java
@@ -2,10 +2,10 @@ package swg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.ObjectsDao;
-import swg.dao.PlayerDao;
-import swg.dao.PlayerObjectDao;
-import swg.dao.PropertyListDao;
+import swg.repository.ObjectsDao;
+import swg.repository.PlayerDao;
+import swg.repository.PlayerObjectDao;
+import swg.repository.PropertyListDao;
import swg.entity.Objects;
import swg.entity.Player;
import swg.entity.PlayerObject;
diff --git a/src/main/java/swg/service/PropertyListService.java b/src/main/java/swg/service/PropertyListService.java
index 0220232..7e822cd 100644
--- a/src/main/java/swg/service/PropertyListService.java
+++ b/src/main/java/swg/service/PropertyListService.java
@@ -2,10 +2,8 @@ package swg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.PropertyListDao;
-import swg.dao.ResourceTypeDao;
+import swg.repository.PropertyListDao;
import swg.entity.PropertyList;
-import swg.entity.ResourceType;
import java.util.List;
diff --git a/src/main/java/swg/service/ResourceTypeService.java b/src/main/java/swg/service/ResourceTypeService.java
index 4e51cd6..c4edb13 100644
--- a/src/main/java/swg/service/ResourceTypeService.java
+++ b/src/main/java/swg/service/ResourceTypeService.java
@@ -2,7 +2,7 @@ package swg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import swg.dao.ResourceTypeDao;
+import swg.repository.ResourceTypeDao;
import swg.entity.ResourceType;
import java.util.List;
diff --git a/src/main/java/swg/service/UasUserDetailsService.java b/src/main/java/swg/service/UasUserDetailsService.java
new file mode 100644
index 0000000..163bd0e
--- /dev/null
+++ b/src/main/java/swg/service/UasUserDetailsService.java
@@ -0,0 +1,8 @@
+package swg.service;
+
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+public interface UasUserDetailsService {
+ UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
+}
diff --git a/src/main/java/swg/service/UserDetailsImpl.java b/src/main/java/swg/service/UserDetailsImpl.java
new file mode 100644
index 0000000..b150461
--- /dev/null
+++ b/src/main/java/swg/service/UserDetailsImpl.java
@@ -0,0 +1,122 @@
+package swg.service;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import swg.entity.UasUser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+public class UserDetailsImpl implements UserDetails {
+ private static final long serialVersionUID = 1L;
+
+ private Long id;
+
+ private String username;
+
+ private String email;
+
+ @JsonIgnore
+ private String password;
+
+ private Collection extends GrantedAuthority> authorities;
+
+ public UserDetailsImpl(Long id, String username, String email, String password, Collection extends GrantedAuthority> authorities) {
+ this.id = id;
+ this.username = username;
+ this.email = email;
+ this.password = password;
+ this.authorities = authorities;
+ }
+
+ public static UserDetailsImpl build(UasUser user) {
+ List authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(user.getUserRole().name()));
+
+ return new UserDetailsImpl(
+ user.getId(),
+ user.getUsername(),
+ user.getEmail(),
+ user.getPassword(),
+ authorities
+ );
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return authorities;
+ }
+
+ public void setAuthorities(Collection extends GrantedAuthority> authorities) {
+ this.authorities = authorities;
+ }
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ UserDetailsImpl user = (UserDetailsImpl) o;
+ return Objects.equals(id, user.id);
+ }
+}
diff --git a/src/main/java/swg/service/UserDetailsServiceImpl.java b/src/main/java/swg/service/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..aaf12c6
--- /dev/null
+++ b/src/main/java/swg/service/UserDetailsServiceImpl.java
@@ -0,0 +1,27 @@
+package swg.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import swg.entity.UasUser;
+import swg.repository.UasUserDao;
+
+import javax.transaction.Transactional;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+ @Autowired
+ UasUserDao uasUserDao;
+
+ @Override
+ @Transactional
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ UasUser user = uasUserDao.findByUsername(username)
+ .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
+
+ return UserDetailsImpl.build(user);
+ }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index a923f3a..2d82172 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -11,3 +11,6 @@ spring.jpa.show-sql=true
spring.application.name=swg-api
spring.config.import=optional:swg-defaults.yml,optional:file:./swg-local.yml
swg.log.config.path=./exe/linux/
+## JWT - Secret plus 24 hour expiration time (86400000)
+swg.app.jwtSecret=smcisbestmc
+swg.app.jwtExpirationMs=86400000