mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-11-29 18:48:23 +08:00
api: Add basic auth
This commit is contained in:
parent
0bb286536b
commit
89f8e2fd55
1
pom.xml
1
pom.xml
@ -259,6 +259,7 @@
|
||||
</tag>
|
||||
</tags>
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -15,6 +15,7 @@
|
||||
<properties>
|
||||
<mysql.version>8.0.28</mysql.version>
|
||||
<h2.version>2.1.214</h2.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<findbugs.version>3.0.1</findbugs.version>
|
||||
<frontend-maven-plugin.version>1.12.1</frontend-maven-plugin.version>
|
||||
<node.version>v16.10.0</node.version>
|
||||
@ -45,6 +46,16 @@
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
|
@ -3,3 +3,6 @@ server.port=9096
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/datacap?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=12345678
|
||||
|
||||
datacap.security.secret=DataCapSecretKey
|
||||
datacap.security.expiration=86400000
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.edurt.datacap.server.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class JwtResponse
|
||||
{
|
||||
private String token;
|
||||
private String type = "Bearer";
|
||||
private Long id;
|
||||
private String username;
|
||||
private List<String> roles;
|
||||
|
||||
public JwtResponse(String accessToken, Long id, String username, List<String> roles)
|
||||
{
|
||||
this.token = accessToken;
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.roles = roles;
|
||||
}
|
||||
}
|
@ -7,7 +7,11 @@ public enum ServiceState
|
||||
PLUGIN_EXECUTE_FAILED(2002, "Plugin execute failed"),
|
||||
REQUEST_VALID_ARGUMENT(3001, "The related parameters cannot be verified"),
|
||||
REQUEST_VALID_ARGUMENT_FORMAT(3002, "Unable to format related parameters"),
|
||||
REQUEST_VALID_ARGUMENT_LAYOUT(3003, "Related parameters cannot be resolved");
|
||||
REQUEST_VALID_ARGUMENT_LAYOUT(3003, "Related parameters cannot be resolved"),
|
||||
USER_NOT_FOUND(4001, "User dose not exists"),
|
||||
USER_ROLE_NOT_FOUND(4002, "User role dose not exists"),
|
||||
USER_UNAUTHORIZED(4003, "Insufficient current user permissions"),
|
||||
USER_EXISTS(4004, "User exists");
|
||||
|
||||
private Integer code;
|
||||
private String value;
|
||||
|
@ -0,0 +1,76 @@
|
||||
package io.edurt.datacap.server.configure;
|
||||
|
||||
import io.edurt.datacap.server.security.AuthTokenFilterService;
|
||||
import io.edurt.datacap.server.security.JwtAuthEntryPoint;
|
||||
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.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(
|
||||
// securedEnabled = true,
|
||||
// jsr250Enabled = true,
|
||||
prePostEnabled = true)
|
||||
public class SecurityConfigure
|
||||
extends WebSecurityConfigurerAdapter
|
||||
{
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final JwtAuthEntryPoint unauthorizedHandler;
|
||||
|
||||
public SecurityConfigure(UserDetailsService userDetailsService, JwtAuthEntryPoint unauthorizedHandler)
|
||||
{
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.unauthorizedHandler = unauthorizedHandler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthTokenFilterService authenticationJwtTokenFilter()
|
||||
{
|
||||
return new AuthTokenFilterService();
|
||||
}
|
||||
|
||||
@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()
|
||||
.anyRequest().authenticated();
|
||||
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package io.edurt.datacap.server.controller;
|
||||
|
||||
import io.edurt.datacap.server.common.JwtResponse;
|
||||
import io.edurt.datacap.server.common.Response;
|
||||
import io.edurt.datacap.server.entity.UserEntity;
|
||||
import io.edurt.datacap.server.service.UserService;
|
||||
import io.edurt.datacap.server.validation.ValidationGroup;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthController
|
||||
{
|
||||
private final UserService userService;
|
||||
|
||||
public AuthController(UserService userService)
|
||||
{
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@PostMapping("/signin")
|
||||
public Response<JwtResponse> authenticateUser(@RequestBody @Validated(ValidationGroup.Crud.Auth.class) UserEntity configure)
|
||||
{
|
||||
return this.userService.authenticate(configure);
|
||||
}
|
||||
|
||||
@PostMapping("/signup")
|
||||
public Response<?> registerUser(@RequestBody @Validated(ValidationGroup.Crud.Create.class) UserEntity configure)
|
||||
{
|
||||
return this.userService.saveOrUpdate(configure);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package io.edurt.datacap.server.entity;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "role")
|
||||
@org.hibernate.annotations.Table(appliesTo = "role", comment = "User rights configuration table")
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class RoleEntity
|
||||
{
|
||||
@Id()
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", columnDefinition = "varchar(1000)")
|
||||
private String description;
|
||||
|
||||
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
||||
private Timestamp createTime;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package io.edurt.datacap.server.entity;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.server.validation.ValidationGroup;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "users",
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = "username")
|
||||
})
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class UserEntity
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotBlank(groups = {
|
||||
ValidationGroup.Crud.Create.class,
|
||||
ValidationGroup.Crud.Update.class,
|
||||
ValidationGroup.Crud.Auth.class
|
||||
})
|
||||
@Size(max = 20)
|
||||
@Column(name = "username")
|
||||
private String username;
|
||||
|
||||
@NotBlank(groups = {
|
||||
ValidationGroup.Crud.Create.class,
|
||||
ValidationGroup.Crud.Update.class,
|
||||
ValidationGroup.Crud.Auth.class
|
||||
})
|
||||
@Size(max = 120)
|
||||
@Column(name = "password")
|
||||
private String password;
|
||||
|
||||
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
||||
private Timestamp createTime;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "user_roles",
|
||||
joinColumns = @JoinColumn(name = "user_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id"))
|
||||
private Set<RoleEntity> roles = new HashSet<>();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.edurt.datacap.server.repository;
|
||||
|
||||
import io.edurt.datacap.server.entity.RoleEntity;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface RoleRepository
|
||||
extends PagingAndSortingRepository<RoleEntity, Long>
|
||||
{
|
||||
Optional<RoleEntity> findByName(String name);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.edurt.datacap.server.repository;
|
||||
|
||||
import io.edurt.datacap.server.entity.UserEntity;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface UserRepository
|
||||
extends PagingAndSortingRepository<UserEntity, Long>
|
||||
{
|
||||
Optional<UserEntity> findByUsername(String username);
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package io.edurt.datacap.server.security;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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 javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public class AuthTokenFilterService
|
||||
extends OncePerRequestFilter
|
||||
{
|
||||
@Autowired
|
||||
private JwtService jwtService;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsServiceImpl userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
try {
|
||||
String jwt = parseJwt(request);
|
||||
if (jwt != null && jwtService.validateJwtToken(jwt)) {
|
||||
String username = jwtService.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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.edurt.datacap.server.security;
|
||||
|
||||
import io.edurt.datacap.server.common.JSON;
|
||||
import io.edurt.datacap.server.common.Response;
|
||||
import io.edurt.datacap.server.common.ServiceState;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JwtAuthEntryPoint
|
||||
implements AuthenticationEntryPoint
|
||||
{
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException authException)
|
||||
throws IOException
|
||||
{
|
||||
log.error("Unauthorized error: {}", authException.getMessage());
|
||||
response.getWriter().print(JSON.toJSON(Response.failure(ServiceState.USER_UNAUTHORIZED)));
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package io.edurt.datacap.server.security;
|
||||
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.MalformedJwtException;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.SignatureException;
|
||||
import io.jsonwebtoken.UnsupportedJwtException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JwtService
|
||||
{
|
||||
@Value("${datacap.security.secret}")
|
||||
private String jwtSecret = "DataCapSecretKey";
|
||||
|
||||
@Value("${datacap.security.expiration}")
|
||||
private int jwtExpirationMs = 86400000;
|
||||
|
||||
public String generateJwtToken(Authentication authentication)
|
||||
{
|
||||
UserDetailsService userPrincipal = (UserDetailsService) authentication.getPrincipal();
|
||||
return Jwts.builder()
|
||||
.setSubject((userPrincipal.getUsername()))
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
|
||||
.signWith(SignatureAlgorithm.HS512, 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) {
|
||||
log.error("Invalid JWT signature: {}", e.getMessage());
|
||||
}
|
||||
catch (MalformedJwtException e) {
|
||||
log.error("Invalid JWT token: {}", e.getMessage());
|
||||
}
|
||||
catch (ExpiredJwtException e) {
|
||||
log.error("JWT token is expired: {}", e.getMessage());
|
||||
}
|
||||
catch (UnsupportedJwtException e) {
|
||||
log.error("JWT token is unsupported: {}", e.getMessage());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
log.error("JWT claims string is empty: {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package io.edurt.datacap.server.security;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.edurt.datacap.server.entity.UserEntity;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class UserDetailsService
|
||||
implements UserDetails
|
||||
{
|
||||
private Long id;
|
||||
private String username;
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
private Collection<? extends GrantedAuthority> authorities;
|
||||
|
||||
public UserDetailsService(Long id, String username, String password,
|
||||
Collection<? extends GrantedAuthority> authorities)
|
||||
{
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
public static UserDetailsService build(UserEntity user)
|
||||
{
|
||||
List<GrantedAuthority> authorities = user.getRoles().stream()
|
||||
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
||||
.collect(Collectors.toList());
|
||||
return new UserDetailsService(
|
||||
user.getId(),
|
||||
user.getUsername(),
|
||||
user.getPassword(),
|
||||
authorities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities()
|
||||
{
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package io.edurt.datacap.server.security;
|
||||
|
||||
import io.edurt.datacap.server.entity.UserEntity;
|
||||
import io.edurt.datacap.server.repository.UserRepository;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
@Service
|
||||
public class UserDetailsServiceImpl
|
||||
implements org.springframework.security.core.userdetails.UserDetailsService
|
||||
{
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public UserDetailsServiceImpl(UserRepository userRepository)
|
||||
{
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserDetails loadUserByUsername(String username)
|
||||
throws UsernameNotFoundException
|
||||
{
|
||||
UserEntity user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
|
||||
return UserDetailsService.build(user);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.edurt.datacap.server.service;
|
||||
|
||||
import io.edurt.datacap.server.common.JwtResponse;
|
||||
import io.edurt.datacap.server.common.Response;
|
||||
import io.edurt.datacap.server.entity.UserEntity;
|
||||
|
||||
public interface UserService
|
||||
{
|
||||
Response<UserEntity> saveOrUpdate(UserEntity configure);
|
||||
|
||||
Response<JwtResponse> authenticate(UserEntity configure);
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package io.edurt.datacap.server.service.impl;
|
||||
|
||||
import io.edurt.datacap.server.common.JwtResponse;
|
||||
import io.edurt.datacap.server.common.Response;
|
||||
import io.edurt.datacap.server.common.ServiceState;
|
||||
import io.edurt.datacap.server.entity.RoleEntity;
|
||||
import io.edurt.datacap.server.entity.UserEntity;
|
||||
import io.edurt.datacap.server.repository.RoleRepository;
|
||||
import io.edurt.datacap.server.repository.UserRepository;
|
||||
import io.edurt.datacap.server.security.JwtService;
|
||||
import io.edurt.datacap.server.security.UserDetailsService;
|
||||
import io.edurt.datacap.server.service.UserService;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
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.stereotype.Service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl
|
||||
implements UserService
|
||||
{
|
||||
private final UserRepository userRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
private final PasswordEncoder encoder;
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final JwtService jwtService;
|
||||
|
||||
public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository, PasswordEncoder encoder, AuthenticationManager authenticationManager, JwtService jwtService)
|
||||
{
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.encoder = encoder;
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<UserEntity> saveOrUpdate(UserEntity configure)
|
||||
{
|
||||
Optional<UserEntity> userOptional = this.userRepository.findByUsername(configure.getUsername());
|
||||
if (userOptional.isPresent()) {
|
||||
return Response.failure(ServiceState.USER_EXISTS);
|
||||
}
|
||||
|
||||
UserEntity user = new UserEntity();
|
||||
user.setUsername(configure.getUsername());
|
||||
user.setPassword(encoder.encode(configure.getPassword()));
|
||||
|
||||
Set<RoleEntity> userRoles = configure.getRoles();
|
||||
Set<RoleEntity> roles = new HashSet<>();
|
||||
if (ObjectUtils.isEmpty(userRoles)) {
|
||||
Optional<RoleEntity> userRoleOptional = roleRepository.findByName("User");
|
||||
if (!userRoleOptional.isPresent()) {
|
||||
return Response.failure(ServiceState.USER_ROLE_NOT_FOUND);
|
||||
}
|
||||
roles.add(userRoleOptional.get());
|
||||
}
|
||||
user.setRoles(roles);
|
||||
return Response.success(userRepository.save(user));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<JwtResponse> authenticate(UserEntity configure)
|
||||
{
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(configure.getUsername(), configure.getPassword());
|
||||
Authentication authentication = authenticationManager.authenticate(authenticationToken);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
String jwt = jwtService.generateJwtToken(authentication);
|
||||
|
||||
UserDetailsService userDetails = (UserDetailsService) authentication.getPrincipal();
|
||||
List<String> roles = userDetails.getAuthorities().stream()
|
||||
.map(item -> item.getAuthority())
|
||||
.collect(Collectors.toList());
|
||||
return Response.success(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), roles));
|
||||
}
|
||||
}
|
@ -23,5 +23,9 @@ public interface ValidationGroup
|
||||
interface Delete
|
||||
extends Crud
|
||||
{}
|
||||
|
||||
interface Auth
|
||||
extends Crud
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,30 @@
|
||||
ALTER TABLE `datacap`.`source`
|
||||
ADD COLUMN `_ssl` boolean default false;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `datacap`.`users`
|
||||
(
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(255) DEFAULT NULL COMMENT ' ',
|
||||
`password` varchar(255) DEFAULT NULL COMMENT ' ',
|
||||
`create_time` datetime(5) DEFAULT CURRENT_TIMESTAMP(5),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARSET = utf8;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `datacap`.`role`
|
||||
(
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) DEFAULT NULL COMMENT ' ',
|
||||
`description` varchar(255) DEFAULT NULL COMMENT ' ',
|
||||
`create_time` datetime(5) DEFAULT CURRENT_TIMESTAMP(5),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARSET = utf8;
|
||||
|
||||
INSERT INTO `datacap`.`role`(`name`, `description`)
|
||||
VALUES ('Admin', 'Admin role'),
|
||||
('User', 'User role');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `datacap`.`user_roles`
|
||||
(
|
||||
`user_id` bigint(20) NOT NULL,
|
||||
`role_id` bigint(20) NOT NULL
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user