diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a877edb
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,206 @@
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.5.RELEASE
+
+ 4.0.0
+ net.alawn
+ bill
+ war
+ 1.0.0-SNAPSHOT
+ bill
+
+
+ UTF-8
+ 1.8
+ 1.4.197
+ 5.1.46
+ 1.1.16
+ 2.8.0
+ 2.0.0
+ 1.18.8
+ 2.1.5.RELEASE
+ 3.7
+ 1.2.54
+ 2.6
+ 4.12
+ 0.10.5
+
+
+
+
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jjwt.version}
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ runtime
+ ${jjwt.version}
+
+
+ junit
+ junit
+ ${junit.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+
+
+
+
+
+
+
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.version}
+
+
+
+
+
+
+
+
+
+
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ ${druid.version}
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger2.version}
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger2.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-batch
+ ${springboot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+ ${springboot.version}
+
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+ ${springboot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-quartz
+ ${springboot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+ ${springboot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ ${springboot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${springboot.version}
+
+
+
+
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ ${mybatis-spring-boot-starter.version}
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${springboot.version}
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ ${springboot.version}
+
+
+
+
+
+ ${project.basedir}/src/main/resources
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.5
+
+ true
+
+ ${project.basedir}/src/test/java
+
+
+
+
+
+
diff --git a/src/main/java/net/alawn/bill/Application.java b/src/main/java/net/alawn/bill/Application.java
new file mode 100644
index 0000000..cb8d778
--- /dev/null
+++ b/src/main/java/net/alawn/bill/Application.java
@@ -0,0 +1,19 @@
+package net.alawn.bill;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+/**
+ * @author Alawn
+ */
+
+@SpringBootApplication
+@EnableJpaAuditing
+@ServletComponentScan(basePackages = {"net.alawn.bill.config"})
+public class Application {
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/src/main/java/net/alawn/bill/config/SwaggerConfig.java b/src/main/java/net/alawn/bill/config/SwaggerConfig.java
new file mode 100644
index 0000000..8d0bcc8
--- /dev/null
+++ b/src/main/java/net/alawn/bill/config/SwaggerConfig.java
@@ -0,0 +1,67 @@
+package net.alawn.bill.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+import java.util.List;
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * @author Alawn
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+ @Bean
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(apiInfo())
+ .select()
+ .apis(RequestHandlerSelectors.basePackage("net.alawn.bill.controller"))
+ .paths(PathSelectors.any())
+ .paths(PathSelectors.regex("^(?!auth).*$"))
+ .build()
+ .securitySchemes(securitySchemes())
+ .securityContexts(securityContexts());
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .title("Book API")
+ .description("Bill接口")
+ .termsOfServiceUrl("http://fairy8.cn")
+ .contact(new Contact("Alawn","fairy8.cn","alawn.cn@gmail.com"))
+ .version("1.0")
+ .build();
+ }
+
+ private List securitySchemes() {
+ return newArrayList(
+ new ApiKey("Authorization", "Authorization", "header"));
+ }
+
+
+ private List securityContexts() {
+ return newArrayList(
+ SecurityContext.builder()
+ .securityReferences(defaultAuth())
+ .forPaths(PathSelectors.regex("^(?!auth).*$"))
+ .build()
+ );
+ }
+ List defaultAuth() {
+ AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+ AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+ authorizationScopes[0] = authorizationScope;
+ return newArrayList(
+ new SecurityReference("Authorization", authorizationScopes));
+ }
+}
+
diff --git a/src/main/java/net/alawn/bill/config/UserIDAuditorBean.java b/src/main/java/net/alawn/bill/config/UserIDAuditorBean.java
new file mode 100644
index 0000000..42851d2
--- /dev/null
+++ b/src/main/java/net/alawn/bill/config/UserIDAuditorBean.java
@@ -0,0 +1,40 @@
+package net.alawn.bill.config;
+
+import net.alawn.bill.security.AuthUser;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.domain.AuditorAware;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import java.util.Optional;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 17:34 2019-05-23
+ */
+
+@Configuration
+public class UserIDAuditorBean implements AuditorAware {
+
+ @Override
+ public Optional getCurrentAuditor() {
+ SecurityContext ctx = SecurityContextHolder.getContext();
+ if (ctx == null) {
+ return Optional.empty();
+ }
+ if (ctx.getAuthentication() == null) {
+ return Optional.empty();
+ }
+ if (ctx.getAuthentication().getPrincipal() == null) {
+ return Optional.empty();
+ }
+ Object principal = ctx.getAuthentication().getPrincipal();
+ if (principal.getClass().isAssignableFrom(AuthUser.class)) {
+ return Optional.ofNullable(((AuthUser) principal).getUsername());
+
+ } else {
+ return Optional.empty();
+ }
+ }
+}
diff --git a/src/main/java/net/alawn/bill/controller/AuthController.java b/src/main/java/net/alawn/bill/controller/AuthController.java
new file mode 100644
index 0000000..cef6bf7
--- /dev/null
+++ b/src/main/java/net/alawn/bill/controller/AuthController.java
@@ -0,0 +1,58 @@
+package net.alawn.bill.controller;
+
+import net.alawn.bill.entity.dto.AddUser;
+import net.alawn.bill.security.JwtAuthenticationRequest;
+import net.alawn.bill.security.JwtAuthenticationResponse;
+import net.alawn.bill.service.AuthService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 09:59 2019-05-23
+ */
+@RestController
+public class AuthController {
+
+ @Value("${jwt.header}")
+ private String tokenHeader;
+
+ @Autowired
+ private AuthService authService;
+
+ @RequestMapping(value = "/auth", method = RequestMethod.POST)
+ public ResponseEntity> createAuthenticationToken(
+ @RequestBody JwtAuthenticationRequest authenticationRequest) throws AuthenticationException {
+ final String token = authService.login(authenticationRequest.getUsername(), authenticationRequest.getPassword());
+
+ // Return the token
+ return ResponseEntity.ok(new JwtAuthenticationResponse(token));
+ }
+
+ @RequestMapping(value = "/auth/refresh", method = RequestMethod.GET)
+ public ResponseEntity> refreshAndGetAuthenticationToken(
+ HttpServletRequest request) throws AuthenticationException{
+ String token = request.getHeader(tokenHeader);
+ String refreshedToken = authService.refresh(token);
+ if(refreshedToken == null) {
+ return ResponseEntity.badRequest().body(null);
+ } else {
+ return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken));
+ }
+ }
+
+ @RequestMapping(value = "/auth/register", method = RequestMethod.POST)
+ public AddUser register(@RequestBody AddUser addedUser) throws AuthenticationException, HttpRequestMethodNotSupportedException {
+ return authService.register(addedUser);
+ }
+}
diff --git a/src/main/java/net/alawn/bill/controller/BasicController.java b/src/main/java/net/alawn/bill/controller/BasicController.java
new file mode 100644
index 0000000..19ec7d8
--- /dev/null
+++ b/src/main/java/net/alawn/bill/controller/BasicController.java
@@ -0,0 +1,126 @@
+package net.alawn.bill.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import net.alawn.bill.entity.dto.AddMerchant;
+import net.alawn.bill.entity.dto.AddPost;
+import net.alawn.bill.entity.dto.AddTitle;
+import net.alawn.bill.entity.po.*;
+import net.alawn.bill.repository.*;
+import net.alawn.bill.security.AuthUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.Optional;
+
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 09:59 2019-05-23
+ */
+
+@Slf4j
+@RequestMapping(value = "/basic")
+@RestController
+public class BasicController {
+
+ @Autowired
+ BookRepo bookRepo;
+
+ @Autowired
+ ItemRepo itemRepo;
+
+ @Autowired
+ UserRepo userRepo;
+
+ @Autowired
+ PostRepo postRepo;
+
+ @Autowired
+ MerchantRepo merchantRepo;
+
+ @Autowired
+ TitleRepo titleRepo;
+
+ @RequestMapping(value = "/post",method = RequestMethod.POST)
+ @ResponseBody
+ public ResponseEntity addPost(@RequestBody AddPost addPost, Principal principal) throws URISyntaxException {
+ AuthUser authUser = (AuthUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ long userId = authUser.getId();
+
+ /** 登记 Post */
+ Post post = addPost.build();
+ post.setUserId(userId);
+ postRepo.save(post);
+ postRepo.flush();
+ return ResponseEntity.ok(post);
+ }
+
+ @RequestMapping(value = "/post/{id}",method = RequestMethod.GET)
+ @ResponseBody
+ public ResponseEntity getPost(@PathVariable long id){
+ log.info("post id:" + id);
+
+ /** 登记 Post */
+ Optional post = postRepo.findById(id);
+
+ if(post.isPresent()) {
+ return ResponseEntity.ok(post.get());
+ }
+ else{
+ return ResponseEntity.noContent().build();
+ }
+ }
+
+
+ @RequestMapping(value = "/merchant",method = RequestMethod.POST)
+ @ResponseBody
+ public ResponseEntity addMerchant(@RequestBody AddMerchant addMerchant) throws URISyntaxException {
+ /** 登记 Post */
+ Merchant merchant = merchantRepo.save(addMerchant.build());
+ merchantRepo.flush();
+ return ResponseEntity.ok(merchant);
+ }
+
+ @RequestMapping(value = "/merchant/{id}",method = RequestMethod.GET)
+ @ResponseBody
+ public ResponseEntity getMerchant(@PathVariable long id){
+ /** 登记 Post */
+ Optional merchant = merchantRepo.findById(id);
+ if(merchant.isPresent()){
+ return ResponseEntity.ok(merchant.get());
+ }
+ else{
+ return ResponseEntity.noContent().build();
+ }
+ }
+
+
+
+ @RequestMapping(value = "/title",method = RequestMethod.POST)
+ @ResponseBody
+ public ResponseEntity addTitle(@RequestBody AddTitle addTitle) throws URISyntaxException {
+ /** 登记 Post */
+ Title title = titleRepo.save(addTitle.build());
+ titleRepo.flush();
+ return ResponseEntity.ok(title);
+ }
+
+ @RequestMapping(value = "/title/{id}",method = RequestMethod.GET)
+ @ResponseBody
+ public ResponseEntity getTitle(@PathVariable long id){
+ /** 登记 Post */
+ Optional title = titleRepo.findById(id);
+ if(title.isPresent()) {
+ return ResponseEntity.ok(title.get());
+ }
+ else{
+ return ResponseEntity.noContent().build();
+ }
+ }
+}
diff --git a/src/main/java/net/alawn/bill/controller/BillController.java b/src/main/java/net/alawn/bill/controller/BillController.java
new file mode 100644
index 0000000..c5313ce
--- /dev/null
+++ b/src/main/java/net/alawn/bill/controller/BillController.java
@@ -0,0 +1,62 @@
+package net.alawn.bill.controller;
+
+import net.alawn.bill.entity.dto.AddBill;
+import net.alawn.bill.entity.po.Book;
+import net.alawn.bill.entity.po.Item;
+import net.alawn.bill.enums.State;
+import net.alawn.bill.repository.BookRepo;
+import net.alawn.bill.repository.ItemRepo;
+import net.alawn.bill.repository.UserRepo;
+import net.alawn.bill.security.AuthUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import java.security.Principal;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 09:59 2019-05-23
+ */
+
+
+@RequestMapping(value = "/bills")
+@RestController
+public class BillController {
+
+ @Autowired
+ BookRepo bookRepo;
+
+ @Autowired
+ ItemRepo itemRepo;
+
+ @Autowired
+ UserRepo userRepo;
+
+ @RequestMapping(value = "/",method = RequestMethod.POST)
+ public ResponseEntity addBook(@RequestBody AddBill addBill, Principal principal){
+ AuthUser authUser = (AuthUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ long userId = authUser.getId();
+
+ /** 登记 book */
+ Book book = bookRepo.save(new Book(userId, addBill.getPostId(), State.APPLIED,new Date(),null));
+
+ /** DTO -> PO 转换 */
+ List- items = addBill.getBillItems()
+ .stream()
+ .map(bill -> new Item(book.getId(),bill.getDating(),bill.getTitleId(),bill.getMerchantId(),bill.getAmount()))
+ .collect(Collectors.toList());
+
+ /** 登记 item */
+ itemRepo.saveAll(items);
+ bookRepo.flush();
+ itemRepo.flush();
+ return ResponseEntity.ok(book);
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/dto/AddBill.java b/src/main/java/net/alawn/bill/entity/dto/AddBill.java
new file mode 100644
index 0000000..3dace38
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/dto/AddBill.java
@@ -0,0 +1,17 @@
+package net.alawn.bill.entity.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:47 2019-05-23
+ */
+
+@Data
+public class AddBill {
+ private long postId;
+ List billItems;
+}
diff --git a/src/main/java/net/alawn/bill/entity/dto/AddMerchant.java b/src/main/java/net/alawn/bill/entity/dto/AddMerchant.java
new file mode 100644
index 0000000..85d8405
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/dto/AddMerchant.java
@@ -0,0 +1,19 @@
+package net.alawn.bill.entity.dto;
+
+import lombok.Data;
+import net.alawn.bill.entity.po.Merchant;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:21 2019-05-23
+ */
+@Data
+public class AddMerchant {
+ private String abbr;
+ private String name;
+
+ public Merchant build() {
+ return Merchant.builder().abbr(abbr).name(name).build();
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/dto/AddPost.java b/src/main/java/net/alawn/bill/entity/dto/AddPost.java
new file mode 100644
index 0000000..6cacc67
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/dto/AddPost.java
@@ -0,0 +1,21 @@
+package net.alawn.bill.entity.dto;
+
+import lombok.Data;
+import net.alawn.bill.entity.po.Post;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:20 2019-05-23
+ */
+
+@Data
+public class AddPost {
+ private String address ;
+ private String contact ;
+ private String mobile ;
+
+ public Post build() {
+ return Post.builder().address(address).contact(contact).mobile(mobile).build();
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/dto/AddTitle.java b/src/main/java/net/alawn/bill/entity/dto/AddTitle.java
new file mode 100644
index 0000000..351df7b
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/dto/AddTitle.java
@@ -0,0 +1,23 @@
+package net.alawn.bill.entity.dto;
+
+import lombok.Data;
+import net.alawn.bill.entity.po.Title;
+
+import java.util.List;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:47 2019-05-23
+ */
+
+@Data
+public class AddTitle {
+ private String name;
+ private String abbr;
+ private String taxNo;
+
+ public Title build() {
+ return Title.builder().abbr(abbr).taxNo(taxNo).name(name).build();
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/dto/AddUser.java b/src/main/java/net/alawn/bill/entity/dto/AddUser.java
new file mode 100644
index 0000000..58376fe
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/dto/AddUser.java
@@ -0,0 +1,20 @@
+package net.alawn.bill.entity.dto;
+
+import lombok.Builder;
+import lombok.Value;
+import net.alawn.bill.entity.po.User;
+
+@Value
+@Builder
+public class AddUser {
+
+ private String username;
+ private String password;
+
+ public User build() {
+ return User.builder()
+ .username(username)
+ .password(password)
+ .build();
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/dto/BillItem.java b/src/main/java/net/alawn/bill/entity/dto/BillItem.java
new file mode 100644
index 0000000..a5b489c
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/dto/BillItem.java
@@ -0,0 +1,20 @@
+package net.alawn.bill.entity.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 11:07 2019-05-23
+ */
+
+@Data
+public class BillItem {
+ private Date dating;
+ private long titleId;
+ private long merchantId;
+ private BigDecimal amount;
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Authority.java b/src/main/java/net/alawn/bill/entity/po/Authority.java
new file mode 100644
index 0000000..781000c
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Authority.java
@@ -0,0 +1,41 @@
+package net.alawn.bill.entity.po;
+
+import lombok.*;
+import org.hibernate.annotations.NotFound;
+import org.hibernate.annotations.NotFoundAction;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+@Data
+@Builder
+@Entity
+@Table(name = "t_bill_authorities")
+@ToString(exclude = {"user"})
+@NoArgsConstructor
+@AllArgsConstructor
+public class Authority{
+
+ @EmbeddedId
+ private AuthorityId id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @NotFound(action = NotFoundAction.IGNORE)
+// @JoinColumn(name = "userId", referencedColumnName = "id")
+ @JoinColumn(name = "userId", referencedColumnName = "id")
+// @MapsId("username")
+ @MapsId("id")
+ private User user;
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o || o instanceof Authority
+ && id != null
+ && id.equals(((Authority) o).id);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31;
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/AuthorityId.java b/src/main/java/net/alawn/bill/entity/po/AuthorityId.java
new file mode 100644
index 0000000..b984d2a
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/AuthorityId.java
@@ -0,0 +1,35 @@
+package net.alawn.bill.entity.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Embeddable;
+import java.io.Serializable;
+
+@Builder
+@Data
+@Embeddable
+@NoArgsConstructor
+@AllArgsConstructor
+public class AuthorityId implements Serializable {
+
+ private static final long serialVersionUID = -8173857210615808268L;
+
+ private Long userId;
+ private String authority;
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o || o instanceof AuthorityId
+ && userId != null && authority != null
+ && userId == ((AuthorityId) o).userId
+ && authority.equals(((AuthorityId) o).authority);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31;
+ }
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Base.java b/src/main/java/net/alawn/bill/entity/po/Base.java
new file mode 100644
index 0000000..f7a952e
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Base.java
@@ -0,0 +1,65 @@
+package net.alawn.bill.entity.po;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import net.alawn.bill.security.AuthUser;
+import org.springframework.data.annotation.*;
+import org.springframework.data.annotation.Version;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import javax.persistence.*;
+import javax.persistence.Id;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author Alawn
+ */
+
+@Data
+@MappedSuperclass
+@Accessors(chain = true)
+@EntityListeners(AuditingEntityListener.class)
+public class Base implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+// @Temporal(TemporalType.TIMESTAMP)
+// @CreationTimestamp
+ @JsonIgnore
+ @CreatedDate
+ @Column(name="create_time")
+ protected Date createTime;
+
+
+ @JsonIgnore
+ @Column(name="create_user")
+ @CreatedBy
+ protected String createUser;
+
+// @Temporal(TemporalType.TIMESTAMP)
+// @UpdateTimestamp
+ @JsonIgnore
+ @LastModifiedDate
+ @Column(name = "update_time")
+ protected Date updateTime;
+
+ @JsonIgnore
+ @Column(name = "update_user")
+ @LastModifiedBy
+ protected String updateUser;
+
+ @JsonIgnore
+ @Version
+ @Column(name = "version")
+ protected Long version;
+
+
+
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Book.java b/src/main/java/net/alawn/bill/entity/po/Book.java
new file mode 100644
index 0000000..631fe56
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Book.java
@@ -0,0 +1,35 @@
+package net.alawn.bill.entity.po;
+
+import lombok.*;
+import net.alawn.bill.enums.State;
+
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:06 2019-05-23
+ */
+
+@Entity
+@Table(name="t_bill_books")
+@Data
+@ToString(callSuper = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class Book extends Base{
+
+ private long userId;
+ private long postId;
+
+ @Enumerated(EnumType.STRING)
+ private State state;
+
+ private Date applyDate;
+ private Date acceptDate;
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Item.java b/src/main/java/net/alawn/bill/entity/po/Item.java
new file mode 100644
index 0000000..55028a8
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Item.java
@@ -0,0 +1,28 @@
+package net.alawn.bill.entity.po;
+
+import lombok.*;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:53 2019-05-23
+ */
+@Entity
+@Table(name = "t_bill_items")
+@Data
+@ToString(callSuper = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class Item extends Base{
+ private long bookId;
+ private Date dating;
+ private long titleId;
+ private long merchantId;
+ private BigDecimal amount;
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Merchant.java b/src/main/java/net/alawn/bill/entity/po/Merchant.java
new file mode 100644
index 0000000..df7c6de
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Merchant.java
@@ -0,0 +1,23 @@
+package net.alawn.bill.entity.po;
+
+import lombok.*;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:59 2019-05-23
+ */
+@Entity
+@Table(name = "t_bill_merchants")
+@Data
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Merchant extends Base{
+ private String abbr;
+ private String name;
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Post.java b/src/main/java/net/alawn/bill/entity/po/Post.java
new file mode 100644
index 0000000..7dbd8ec
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Post.java
@@ -0,0 +1,27 @@
+package net.alawn.bill.entity.po;
+
+import lombok.*;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:17 2019-05-23
+ */
+
+@Entity
+@Table(name = "t_bill_posts")
+@Data
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Post extends Base{
+ private long userId ;
+ private String address ;
+ private String contact ;
+ private String mobile ;
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/Title.java b/src/main/java/net/alawn/bill/entity/po/Title.java
new file mode 100644
index 0000000..8d88404
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/Title.java
@@ -0,0 +1,26 @@
+package net.alawn.bill.entity.po;
+
+import lombok.*;
+
+import javax.persistence.*;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 10:17 2019-05-23
+ */
+
+@Entity
+@Table(name = "t_bill_titles")
+@Data
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Title extends Base{
+
+ private String name;
+ private String abbr;
+ @Column(length = 18)
+ private String taxNo;
+}
diff --git a/src/main/java/net/alawn/bill/entity/po/User.java b/src/main/java/net/alawn/bill/entity/po/User.java
new file mode 100644
index 0000000..7f35854
--- /dev/null
+++ b/src/main/java/net/alawn/bill/entity/po/User.java
@@ -0,0 +1,84 @@
+package net.alawn.bill.entity.po;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author Alawn
+ */
+
+@SuppressWarnings("ALL")
+@Entity
+@Builder
+@Table(
+ name = "t_bill_users",
+ indexes = {
+ @Index(name = "t_bill_users_idx1",columnList = "create_time",unique = false),
+ @Index(name = "t_bill_users_idx2",columnList = "username",unique = true)})
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString(exclude = {"authorities"})
+@Slf4j
+public class User extends Base {
+
+ /** 用户名称 */
+ private String username;
+
+ /** 密钥 */
+ @JsonIgnore
+ private String password;
+
+ /** 密钥 */
+ private String secret;
+
+ /** 密码盐 */
+ private String salt;
+
+ /** token因子 */
+ private String tokenFactor;
+
+ /** 邮箱 */
+ private String email;
+
+ /** 上一次重置密码时间 */
+ private Date lastPasswordResetDate;
+
+ @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
+ private Set authorities;
+
+ @Builder.Default
+ private boolean enabled = true;
+
+// public UserDetails toUserDetails() {
+// log.info("toUserDetails.authorities:" + authorities);
+// log.info("toUserDetails.authorities:" + mapToGrantedAuthorities(authorities));
+// return new AuthUser(id,username, password, email,enabled, mapToGrantedAuthorities(authorities),lastPasswordResetDate);
+// }
+//
+//// private static Set mapToGrantedAuthorities(Set authorities) {
+//// return authorities.stream()
+//// .map(authority -> new SimpleGrantedAuthority(authority.getId().getAuthority()))
+//// .collect(Collectors.toSet());
+//// }
+
+// private static Set mapToGrantedAuthorities(Set authorities) {
+// log.info("authorities:" + authorities);
+// log.info("authorities.stream().toString():" + authorities.stream().toString());
+// return authorities.stream()
+// .map(authority -> new SimpleGrantedAuthority(authority.getId().getAuthority()))
+// .collect(Collectors.toSet());
+// }
+}
diff --git a/src/main/java/net/alawn/bill/enums/AccessProtocol.java b/src/main/java/net/alawn/bill/enums/AccessProtocol.java
new file mode 100644
index 0000000..110e90a
--- /dev/null
+++ b/src/main/java/net/alawn/bill/enums/AccessProtocol.java
@@ -0,0 +1,57 @@
+package net.alawn.bill.enums;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:01 2019-03-23
+ */
+
+public enum AccessProtocol {
+
+ /**
+ * 本地直接访问
+ */
+ DIRECT("本地直接访问"),
+
+ /**
+ * Net File System
+ */
+ NFS("Net File System"),
+ /**
+ * Server Message Block
+ */
+ SMB("Server Message Block"),
+ /**
+ * File Transfer Protocol
+ */
+ FTP("File Transfer Protocol"),
+
+ /**
+ * Apple Filing Protocol
+ */
+ AFP("Apple Filing Protocol"),
+
+ /**
+ * Based on Secure Shell Communication Protocol
+ */
+ SCP("Secure Copy"),
+ /**
+ * Web Distributed Authoring and Version
+ */
+ WebDAV("Web Distributed Authoring and Version");
+
+
+ private String value;
+
+ AccessProtocol(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
diff --git a/src/main/java/net/alawn/bill/enums/State.java b/src/main/java/net/alawn/bill/enums/State.java
new file mode 100644
index 0000000..676defc
--- /dev/null
+++ b/src/main/java/net/alawn/bill/enums/State.java
@@ -0,0 +1,28 @@
+package net.alawn.bill.enums;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:01 2019-03-23
+ */
+
+public enum State {
+
+ APPLIED ( "已申请"),
+ ACCEPTED ( "已受理"),
+ POSTED ( "已快递");
+
+ private String desc;
+
+ State(String desc) {
+ this.desc = desc;
+ }
+
+ public String desc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+}
diff --git a/src/main/java/net/alawn/bill/exception/CommonException.java b/src/main/java/net/alawn/bill/exception/CommonException.java
new file mode 100644
index 0000000..c124934
--- /dev/null
+++ b/src/main/java/net/alawn/bill/exception/CommonException.java
@@ -0,0 +1,35 @@
+package net.alawn.bill.exception;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 12:47 2019-03-29
+ */
+
+@Slf4j
+@Data
+public class CommonException extends RuntimeException{
+ protected String code;
+ protected String message;
+
+ public CommonException(String code, String message) {
+ super(message);
+ this.code = code;
+ this.message = message;
+ }
+
+ public CommonException(String code, String format, Object... arguments) {
+ super(String.format(format,arguments));
+ this.code = code;
+ this.message = String.format(format,arguments);
+ }
+
+ public CommonException(RespMsg msg) {
+ super(msg.message());
+ this.message = msg.message();
+ this.code = msg.code();
+ }
+}
diff --git a/src/main/java/net/alawn/bill/exception/RespMsg.java b/src/main/java/net/alawn/bill/exception/RespMsg.java
new file mode 100644
index 0000000..8bb6f23
--- /dev/null
+++ b/src/main/java/net/alawn/bill/exception/RespMsg.java
@@ -0,0 +1,45 @@
+package net.alawn.bill.exception;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 17:55 2019-04-12
+ */
+public enum RespMsg {
+
+ NO_STORAGE_FOUND ( "200003", RespMsgConstants.NO_STORAGE_FOUND ) ,
+ BLOB_DUPLICATE ( "200004", RespMsgConstants.BLOB_DUPLICATE ) ,
+ BLOB_NOT_EXIST ( "200005", RespMsgConstants.BLOB_NOT_EXIST ) ,
+ NO_BLOB_FOUND ( "200006", RespMsgConstants.NO_BLOB_FOUND ) ,
+ BUCKET_DUPLICATE ( "200007", RespMsgConstants.BUCKET_DUPLICATE ) ,
+ FILE_HANDLING ( "200008", RespMsgConstants.FILE_HANDLING ) ,
+ FILE_NOT_EXIST ( "200009", RespMsgConstants.FILE_NOT_EXIST ) ,
+ FILE_OCCUPIED ( "200010", RespMsgConstants.FILE_OCCUPIED ) ,
+ NO_ACCESS_PERMISSION ( "200011", RespMsgConstants.NO_ACCESS_PERMISSION ) ,
+ NO_BUCKET_FOUND ( "200012", RespMsgConstants.NO_BUCKET_FOUND ) ,
+ NO_DEFAULT_BUCKET ( "200013", RespMsgConstants.NO_DEFAULT_BUCKET ) ,
+ NO_DEFAULT_STORAGE ( "200014", RespMsgConstants.NO_DEFAULT_STORAGE ) ,
+ REQUEST_PARAMS ( "200015", RespMsgConstants.REQUEST_PARAMS ) ,
+ INTERNAL_ERROR ( "200016", RespMsgConstants.INTERNAL_ERROR ) ,
+ NO_DATA ( "200017", RespMsgConstants.NO_DATA ) ,
+ USER_ALREADY_EXIST ( "200018", RespMsgConstants.USER_ALREADY_EXIST ) ,
+ USER_NOT_EXIST_OR_PASSWORD_INCORRECT ( "200019", RespMsgConstants.USER_NOT_EXIST_OR_PASSWORD_INCORRECT ) ,
+ SUCCESS ( "000000", RespMsgConstants.SUCCESS ) ;
+
+
+ private String code;
+ private String message;
+
+ RespMsg(String code, String message) {
+ this.code = code ;
+ this.message = message ;
+ }
+
+ public String code()
+ {
+ return code;
+ }
+
+ public String message() { return message; }
+
+}
diff --git a/src/main/java/net/alawn/bill/exception/RespMsgConstants.java b/src/main/java/net/alawn/bill/exception/RespMsgConstants.java
new file mode 100644
index 0000000..ef5cd2e
--- /dev/null
+++ b/src/main/java/net/alawn/bill/exception/RespMsgConstants.java
@@ -0,0 +1,28 @@
+package net.alawn.bill.exception;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 13:21 2019-03-29
+ */
+public final class RespMsgConstants {
+
+ public final static String NO_STORAGE_FOUND = "没有发现存储" ;
+ public final static String BLOB_DUPLICATE = "发现重复Blob" ;
+ public final static String BLOB_NOT_EXIST = "Blob对象不存在" ;
+ public final static String NO_BLOB_FOUND = "Blob对象不存在" ;
+ public final static String BUCKET_DUPLICATE = "发现重复Bucket" ;
+ public final static String FILE_HANDLING = "文件处理异常" ;
+ public final static String FILE_NOT_EXIST = "文件不存在" ;
+ public final static String FILE_OCCUPIED = "文件/文件夹已被占用" ;
+ public final static String NO_ACCESS_PERMISSION = "没有该访问权限" ;
+ public final static String NO_BUCKET_FOUND = "没有找到Bucket" ;
+ public final static String NO_DEFAULT_BUCKET = "没有找到默认Bucket" ;
+ public final static String NO_DEFAULT_STORAGE = "没有找到默认存储设备" ;
+ public final static String REQUEST_PARAMS = "请求参数有误" ;
+ public final static String INTERNAL_ERROR = "内部错误" ;
+ public final static String NO_DATA = "没有数据" ;
+ public final static String USER_ALREADY_EXIST = "用户已存在" ;
+ public final static String USER_NOT_EXIST_OR_PASSWORD_INCORRECT = "用户不存在或密码不正确" ;
+ public final static String SUCCESS = "业务成功" ;
+}
diff --git a/src/main/java/net/alawn/bill/exception/UserAlreadyExistException.java b/src/main/java/net/alawn/bill/exception/UserAlreadyExistException.java
new file mode 100644
index 0000000..e978a46
--- /dev/null
+++ b/src/main/java/net/alawn/bill/exception/UserAlreadyExistException.java
@@ -0,0 +1,24 @@
+package net.alawn.bill.exception;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:52 2019-03-28
+ */
+
+public class UserAlreadyExistException extends CommonException {
+
+ private final static RespMsg msg = RespMsg.USER_ALREADY_EXIST;
+
+ public UserAlreadyExistException() {
+ super(msg.code(),msg.message());
+ }
+
+ public UserAlreadyExistException(String message) {
+ super(msg.code(),message);
+ }
+
+ public UserAlreadyExistException(String format, Object... arguments) {
+ super(msg.code(),format, arguments);
+ }
+}
diff --git a/src/main/java/net/alawn/bill/repository/AuthorityRepo.java b/src/main/java/net/alawn/bill/repository/AuthorityRepo.java
new file mode 100644
index 0000000..d0de133
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/AuthorityRepo.java
@@ -0,0 +1,10 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.Authority;
+import net.alawn.bill.entity.po.AuthorityId;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface AuthorityRepo extends JpaRepository {
+}
diff --git a/src/main/java/net/alawn/bill/repository/BookRepo.java b/src/main/java/net/alawn/bill/repository/BookRepo.java
new file mode 100644
index 0000000..e4c5b37
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/BookRepo.java
@@ -0,0 +1,16 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.Book;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 11:14 2019-05-23
+ */
+
+@Repository
+public interface BookRepo extends JpaRepository {
+
+}
diff --git a/src/main/java/net/alawn/bill/repository/ItemRepo.java b/src/main/java/net/alawn/bill/repository/ItemRepo.java
new file mode 100644
index 0000000..c641762
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/ItemRepo.java
@@ -0,0 +1,17 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.Book;
+import net.alawn.bill.entity.po.Item;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 11:14 2019-05-23
+ */
+
+@Repository
+public interface ItemRepo extends JpaRepository
- {
+
+}
diff --git a/src/main/java/net/alawn/bill/repository/MerchantRepo.java b/src/main/java/net/alawn/bill/repository/MerchantRepo.java
new file mode 100644
index 0000000..e7cfa44
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/MerchantRepo.java
@@ -0,0 +1,17 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.Item;
+import net.alawn.bill.entity.po.Merchant;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 11:14 2019-05-23
+ */
+
+@Repository
+public interface MerchantRepo extends JpaRepository {
+
+}
diff --git a/src/main/java/net/alawn/bill/repository/PostRepo.java b/src/main/java/net/alawn/bill/repository/PostRepo.java
new file mode 100644
index 0000000..473bdb3
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/PostRepo.java
@@ -0,0 +1,17 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.Item;
+import net.alawn.bill.entity.po.Post;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 11:14 2019-05-23
+ */
+
+@Repository
+public interface PostRepo extends JpaRepository {
+
+}
diff --git a/src/main/java/net/alawn/bill/repository/TitleRepo.java b/src/main/java/net/alawn/bill/repository/TitleRepo.java
new file mode 100644
index 0000000..201ef01
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/TitleRepo.java
@@ -0,0 +1,17 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.Post;
+import net.alawn.bill.entity.po.Title;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 11:14 2019-05-23
+ */
+
+@Repository
+public interface TitleRepo extends JpaRepository {
+
+}
diff --git a/src/main/java/net/alawn/bill/repository/UserRepo.java b/src/main/java/net/alawn/bill/repository/UserRepo.java
new file mode 100644
index 0000000..a63bd27
--- /dev/null
+++ b/src/main/java/net/alawn/bill/repository/UserRepo.java
@@ -0,0 +1,10 @@
+package net.alawn.bill.repository;
+
+import net.alawn.bill.entity.po.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserRepo extends JpaRepository {
+ User findByUsername(String username);
+}
diff --git a/src/main/java/net/alawn/bill/security/AuthUser.java b/src/main/java/net/alawn/bill/security/AuthUser.java
new file mode 100644
index 0000000..e4ac365
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/AuthUser.java
@@ -0,0 +1,90 @@
+package net.alawn.bill.security;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.ToString;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Date;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 16:09 2019-05-20
+ */
+@ToString(callSuper = true)
+public class AuthUser implements UserDetails {
+ private final long id;
+ private final String username;
+ private final String password;
+ private final boolean enabled;
+ private final Collection extends GrantedAuthority> authorities;
+ private final Date lastPasswordResetDate;
+
+ public AuthUser(long id, String username, String password, String email, boolean enabled, Collection extends GrantedAuthority> authorities, Date lastPasswordResetDate) {
+ this.id = id;
+ this.username = username;
+ this.password = password;
+ this.enabled = enabled;
+ this.authorities = authorities;
+ this.lastPasswordResetDate = lastPasswordResetDate;
+ }
+
+ // 返回分配给用户的角色列表
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return authorities;
+ }
+
+ @JsonIgnore
+ public long getId() {
+ return id;
+ }
+
+ @JsonIgnore
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public String getUsername() {
+ return username;
+ }
+
+ // 账户是否未过期
+ @JsonIgnore
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ // 账户是否未锁定
+ @JsonIgnore
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ // 密码是否未过期
+ @JsonIgnore
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ // 账户是否激活
+ @JsonIgnore
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+ // 这个是自定义的,返回上次密码重置日期
+ @JsonIgnore
+ public Date getLastPasswordResetDate() {
+ return lastPasswordResetDate;
+ }
+
+
+}
diff --git a/src/main/java/net/alawn/bill/security/AuthUserDetailsServiceImpl.java b/src/main/java/net/alawn/bill/security/AuthUserDetailsServiceImpl.java
new file mode 100644
index 0000000..c962a4a
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/AuthUserDetailsServiceImpl.java
@@ -0,0 +1,33 @@
+package net.alawn.bill.security;
+
+import net.alawn.bill.entity.po.User;
+import net.alawn.bill.repository.UserRepo;
+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;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 16:46 2019-05-20
+ */
+@Service("authUserDetailsService")
+public class AuthUserDetailsServiceImpl implements UserDetailsService {
+
+ @Autowired
+ private UserRepo userRepo;
+
+ @Override
+ public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
+
+ User user = userRepo.findByUsername(name);
+
+ if (user == null) {
+ throw new UsernameNotFoundException("UsernameNotFoundException");
+ } else {
+ return UserFactory.createAuthUser(user);
+ }
+ }
+}
diff --git a/src/main/java/net/alawn/bill/security/JwtAuthenticationEntryPoint.java b/src/main/java/net/alawn/bill/security/JwtAuthenticationEntryPoint.java
new file mode 100644
index 0000000..69b478d
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/JwtAuthenticationEntryPoint.java
@@ -0,0 +1,25 @@
+package net.alawn.bill.security;
+
+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;
+import java.io.Serializable;
+
+@Component
+public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
+
+ private static final long serialVersionUID = -8970718410437077606L;
+
+ @Override
+ public void commence(HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException authException) throws IOException {
+ // This is invoked when user tries to access a secured REST resource without supplying any credentials
+ // We should just send a 401 Unauthorized response because there is no 'login page' to redirect to
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+ }
+}
diff --git a/src/main/java/net/alawn/bill/security/JwtAuthenticationRequest.java b/src/main/java/net/alawn/bill/security/JwtAuthenticationRequest.java
new file mode 100644
index 0000000..af289b2
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/JwtAuthenticationRequest.java
@@ -0,0 +1,15 @@
+package net.alawn.bill.security;
+
+import lombok.Data;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 17:29 2019-05-20
+ */
+
+@Data
+public class JwtAuthenticationRequest {
+ private String username;
+ private String password;
+}
diff --git a/src/main/java/net/alawn/bill/security/JwtAuthenticationResponse.java b/src/main/java/net/alawn/bill/security/JwtAuthenticationResponse.java
new file mode 100644
index 0000000..9ddcf11
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/JwtAuthenticationResponse.java
@@ -0,0 +1,20 @@
+package net.alawn.bill.security;
+
+import lombok.Data;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 17:30 2019-05-20
+ */
+
+@Data
+public class JwtAuthenticationResponse {
+
+ private String token;
+
+ public JwtAuthenticationResponse(String token) {
+ this.token = token;
+ }
+
+}
diff --git a/src/main/java/net/alawn/bill/security/JwtAuthenticationTokenFilter.java b/src/main/java/net/alawn/bill/security/JwtAuthenticationTokenFilter.java
new file mode 100644
index 0000000..7737bc3
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/JwtAuthenticationTokenFilter.java
@@ -0,0 +1,74 @@
+package net.alawn.bill.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+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;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 16:24 2019-05-20
+ */
+
+
+@Component
+public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
+
+ @Qualifier("authUserDetailsService")
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ private JwtTokenUtil jwtTokenUtil;
+
+ @Value("${jwt.header}")
+ private String tokenHeader;
+
+ @Value("${jwt.tokenHead}")
+ private String tokenHead;
+
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+// logger.info("doFilterInternal");
+// String authHeader = request.getHeader("Authorization");
+ String authHeader = request.getHeader(this.tokenHeader);
+// logger.info("authHeader:" + authHeader);
+
+// if (authHeader != null && authHeader.startsWith("Bearer ")) {
+ if (authHeader != null && authHeader.startsWith(tokenHead)) {
+ final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
+ logger.info("authToken:" + authToken);
+ String username = jwtTokenUtil.getUsernameFromToken(authToken);
+// logger.info("username" + username);
+// logger.info("checking authentication " + username);
+
+ if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
+
+ AuthUser authUser = (AuthUser) this.userDetailsService.loadUserByUsername(username);
+ logger.info("userDetails:" + authUser);
+
+ if (jwtTokenUtil.validateToken(authToken, authUser)) {
+ UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities());
+ authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails( request));
+ logger.info("authenticated user " + username + ", setting security context");
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ }
+ }
+ filterChain.doFilter(request, response);
+ }
+}
+
diff --git a/src/main/java/net/alawn/bill/security/JwtTokenUtil.java b/src/main/java/net/alawn/bill/security/JwtTokenUtil.java
new file mode 100644
index 0000000..eeba732
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/JwtTokenUtil.java
@@ -0,0 +1,178 @@
+package net.alawn.bill.security;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.Keys;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Service;
+
+import javax.crypto.SecretKey;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 17:50 2019-05-17
+ */
+
+@Slf4j
+@Service
+public class JwtTokenUtil {
+// private static Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256) ;
+ @Value("${jwt.secret}")
+ private String secret;// = "11111111111111111111111111111111";
+ @Value("${jwt.expiration}")
+ private long expiration;
+ private static final String issuer = "bill" ;
+ private static final String subject = "bill" ;
+ private static final String CLAIM_KEY_USERNAME = "sub" ;
+ private static final String CLAIM_KEY_CREATED = "created" ;
+
+ /**
+ * 签发JWT
+ */
+ public String generateToken(UserDetails userDetails) {
+ Map claims = new HashMap<>();
+ claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
+ claims.put(CLAIM_KEY_CREATED, new Date());
+ return generateToken(claims);
+ }
+
+ String generateToken(Map claims) {
+ log.info("secret:" + secret);
+// Key key = Keys.hmacShaKeyFor(secret.getBytes());
+ return Jwts.builder()
+ .setSubject(subject)
+ .setIssuer(issuer)
+ .setClaims(claims)
+ .setIssuedAt(new Date())
+ .setExpiration(generateExpirationDate())
+ .signWith(generalKey())
+ .compact();
+ }
+
+
+ public boolean canTokenBeRefreshed(String token,Date lastPasswordReset) {
+ final Date created = getCreatedDateFromToken(token);
+ return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
+ && !isTokenExpired(token);
+ }
+
+ public String getUsernameFromToken(String token) {
+ String username;
+ try {
+ final Claims claims = getClaimsFromToken(token);
+ log.info("claims:" + claims);
+// username = claims.getSubject();
+ username = (String) claims.get(CLAIM_KEY_USERNAME);
+ log.info("username:" + username);
+ } catch (Exception e) {
+ e.printStackTrace();
+ username = null;
+ }
+ return username;
+ }
+
+ public String refreshToken(String token) {
+ String refreshedToken;
+ try {
+ final Claims claims = getClaimsFromToken(token);
+ claims.put(CLAIM_KEY_CREATED, new Date());
+ refreshedToken = generateToken(claims);
+ } catch (Exception e) {
+ refreshedToken = null;
+ }
+ return refreshedToken;
+ }
+
+ /**
+ * 验证JWT
+ */
+ public boolean validateToken(String token, UserDetails userDetails)
+ {
+// User user = userDetails;
+ String username = getUsernameFromToken( token );
+ return (username.equals( userDetails.getUsername() ) && !isTokenExpired( token ));
+ }
+
+ /**
+ * 获取token是否过期
+ */
+ public Boolean isTokenExpired(String token) {
+ Date expiration = getExpirationDateFromToken( token );
+ return expiration.before( new Date() );
+ }
+
+ /**
+ * 获取token的过期时间
+ */
+ public Date getExpirationDateFromToken(String token) {
+ Date expiration = getClaimsFromToken( token ).getExpiration();
+ return expiration;
+ }
+
+ /**
+ * 解析JWT
+ */
+ private Claims getClaimsFromToken(String token) {
+ log.info("getClaimsFromToken");
+ log.info("secret:" + secret);
+// Key key = Keys.hmacShaKeyFor(secret.getBytes());
+ Claims claims = Jwts.parser()
+ .setSigningKey(generalKey())
+ .parseClaimsJws(token)
+ .getBody();
+ log.info("claims:" + claims);
+ return claims;
+ }
+
+ private Date generateExpirationDate() {
+ return new Date(System.currentTimeMillis() + expiration * 1000);
+ }
+
+ private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
+ return (lastPasswordReset != null && created.before(lastPasswordReset));
+ }
+
+ public Date getCreatedDateFromToken(String token) {
+ Date created;
+ try {
+ final Claims claims = getClaimsFromToken(token);
+ created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
+ } catch (Exception e) {
+ created = null;
+ }
+ return created;
+ }
+
+ private SecretKey generalKey(){
+ log.info("generalKey");
+ log.info("secret:" + secret);
+ byte[] encodedKey = null;
+// try {
+//// encodedKey = Base64.decodeBase64(secret.getBytes("UTF-8"));
+// }
+// catch (Exception e)
+// {
+// e.printStackTrace();
+// }
+// log.info("encodedKey:" + encodedKey);
+// SecretKey key = Keys.hmacShaKeyFor(encodedKey);
+
+
+ SecretKey key = null;
+ try {
+ key = Keys.hmacShaKeyFor(secret.getBytes("UTF-8"));
+ }
+ catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ return key;
+ }
+}
diff --git a/src/main/java/net/alawn/bill/security/UserFactory.java b/src/main/java/net/alawn/bill/security/UserFactory.java
new file mode 100644
index 0000000..9298890
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/UserFactory.java
@@ -0,0 +1,46 @@
+package net.alawn.bill.security;
+
+import net.alawn.bill.entity.po.Authority;
+import net.alawn.bill.entity.po.User;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 16:45 2019-05-20
+ */
+public class UserFactory {
+
+ private UserFactory() {
+ }
+
+ public static AuthUser createAuthUser(User user) {
+// user.toUserDetails();
+ return new AuthUser(
+ user.getId(),
+ user.getUsername(),
+ user.getPassword(),
+ user.getEmail(),
+ user.isEnabled(),
+ mapToGrantedAuthorities(user.getAuthorities()),
+ user.getLastPasswordResetDate()
+ );
+ }
+
+ private static Set mapToGrantedAuthorities(Set authorities) {
+ return authorities.stream()
+ .map(authority -> new SimpleGrantedAuthority(authority.getId().getAuthority()))
+ .collect(Collectors.toSet());
+ }
+// private static List mapToGrantedAuthorities(List authorities) {
+// return authorities.stream()
+// .map(SimpleGrantedAuthority::new)
+// .collect(Collectors.toList());
+// }
+}
diff --git a/src/main/java/net/alawn/bill/security/WebSecurityConfig.java b/src/main/java/net/alawn/bill/security/WebSecurityConfig.java
new file mode 100644
index 0000000..e7c8a30
--- /dev/null
+++ b/src/main/java/net/alawn/bill/security/WebSecurityConfig.java
@@ -0,0 +1,143 @@
+package net.alawn.bill.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.BeanIds;
+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.builders.WebSecurity;
+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;
+import org.springframework.security.web.firewall.HttpFirewall;
+import org.springframework.security.web.firewall.StrictHttpFirewall;
+import org.springframework.util.DigestUtils;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 16:53 2019-05-17
+ */
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Qualifier("authUserDetailsService")
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ private JwtAuthenticationEntryPoint unauthorizedHandler;
+
+ @Bean
+ public JwtAuthenticationTokenFilter authenticationTokenFilterBean(){
+ return new JwtAuthenticationTokenFilter();
+ }
+
+ @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ @Autowired
+ public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
+ authenticationManagerBuilder
+ // 设置UserDetailsService
+ .userDetailsService(this.userDetailsService)
+ // 使用BCrypt进行密码的hash
+ .passwordEncoder(passwordEncoder());
+
+ }
+
+ /** 装载BCrypt密码编码器 */
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ /** 自定义防火墙 */
+ @Bean
+ public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
+ StrictHttpFirewall firewall = new StrictHttpFirewall();
+ firewall.setAllowUrlEncodedSlash(true);
+ firewall.setAllowSemicolon(true);
+ return firewall;
+ }
+
+ /** Security Http 配置 */
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable() // 去掉跨域
+ .exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
+ .and()
+ .authorizeRequests()
+ .antMatchers("/").permitAll()
+ .antMatchers("/druid/**").permitAll()
+ .antMatchers("/swagger*").permitAll()
+ .antMatchers( HttpMethod.GET, "/","/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
+ .antMatchers("/auth/**").permitAll()
+ .antMatchers("/bill/**").authenticated()
+ .antMatchers("/basic/**/*").authenticated()
+// .antMatchers("/auth/**").permitAll().anyRequest().authenticated()
+ .and()
+ .formLogin().loginPage("/").permitAll()
+ .and()
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 去掉Session
+ .and()
+ .logout().permitAll() ;
+
+ // 添加JWT logger
+ http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
+
+ // 禁用缓存
+ http.headers().cacheControl(); // 禁用缓存
+ }
+
+ /** Security Web 配置 */
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ super.configure(web);
+ // @formatter:off
+ web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
+ }
+
+ /** Security Authentication 配置 */
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+// auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
+
+ //校验用户
+ auth.userDetailsService(userDetailsService).passwordEncoder( new PasswordEncoder() {
+ //对密码进行加密
+ @Override
+ public String encode(CharSequence charSequence) {
+ System.out.println(charSequence.toString());
+ return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
+ }
+ //对密码进行判断匹配
+ @Override
+ public boolean matches(CharSequence charSequence, String s) {
+ String encode = DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
+ boolean res = s.equals( encode );
+ return res;
+ }
+ } );
+ }
+// @Override
+// public void configure(AuthenticationManagerBuilder auth) throws Exception {
+// // 使用自定义身份验证组件
+// auth.authenticationProvider(new CustomAuthenticationProvider(userDetailsService));
+// }
+
+}
diff --git a/src/main/java/net/alawn/bill/service/AuthService.java b/src/main/java/net/alawn/bill/service/AuthService.java
new file mode 100644
index 0000000..185dc69
--- /dev/null
+++ b/src/main/java/net/alawn/bill/service/AuthService.java
@@ -0,0 +1,16 @@
+package net.alawn.bill.service;
+
+import net.alawn.bill.entity.dto.AddUser;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:58 2019-05-20
+ */
+public interface AuthService {
+ AddUser register(AddUser userDTO) throws HttpRequestMethodNotSupportedException, AuthenticationException;
+ String login(String username, String password);
+ String refresh(String oldToken);
+}
diff --git a/src/main/java/net/alawn/bill/service/impl/AuthServiceImpl.java b/src/main/java/net/alawn/bill/service/impl/AuthServiceImpl.java
new file mode 100644
index 0000000..76594a2
--- /dev/null
+++ b/src/main/java/net/alawn/bill/service/impl/AuthServiceImpl.java
@@ -0,0 +1,120 @@
+package net.alawn.bill.service.impl;
+
+import net.alawn.bill.entity.dto.AddUser;
+import net.alawn.bill.entity.po.Authority;
+import net.alawn.bill.entity.po.AuthorityId;
+import net.alawn.bill.entity.po.User;
+import net.alawn.bill.exception.CommonException;
+import net.alawn.bill.exception.RespMsg;
+import net.alawn.bill.repository.AuthorityRepo;
+import net.alawn.bill.repository.UserRepo;
+import net.alawn.bill.security.AuthUser;
+import net.alawn.bill.security.JwtTokenUtil;
+import net.alawn.bill.service.AuthService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * @Author: Alawn
+ * @Description:
+ * @Date: Create in 15:59 2019-05-20
+ */
+
+@Service
+//@AllArgsConstructor(onConstructor = @__(@Autowired))
+public class AuthServiceImpl implements AuthService {
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Qualifier("authUserDetailsService")
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ private JwtTokenUtil jwtTokenUtil;
+
+ @Autowired
+ private UserRepo userRepo ;
+
+ @Value("${jwt.tokenHead}")
+ private String tokenHead;
+
+ @Autowired
+ private AuthorityRepo authorityRepo;
+
+
+// @Autowired
+// public AuthServiceImpl(AuthenticationManager authenticationManager) {
+// this.authenticationManager = authenticationManager;
+// }
+
+ @Override
+ public AddUser register(AddUser userDTO) throws AuthenticationException {
+ final String username = userDTO.getUsername();
+
+ if(userRepo.findByUsername(username) != null) {
+ throw new CommonException(RespMsg.USER_ALREADY_EXIST);
+ }
+
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+ final String rawPassword = userDTO.getPassword();
+ User user = User.builder()
+ .username(username)
+ .password(encoder.encode(rawPassword)).build();
+ User saved = userRepo.save(user);
+ Authority savedAuth = authorityRepo.save(
+ Authority.builder()
+ .user(saved)
+ .id(AuthorityId.builder()
+ .userId(saved.getId())
+ .authority("ROLE_USER")
+ .build())
+ .build());
+ userRepo.flush();
+ authorityRepo.flush();
+ return userDTO;
+ }
+
+
+ @Override
+ public String login(String username, String password) {
+ UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
+ final Authentication authentication = authenticationManager.authenticate(upToken);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+ final String token = jwtTokenUtil.generateToken(userDetails);
+ return token;
+ }
+
+ @Override
+ public String refresh(String oldToken) {
+ final String token = oldToken.substring(tokenHead.length());
+ String username = jwtTokenUtil.getUsernameFromToken(token);
+ AuthUser user = (AuthUser)userDetailsService.loadUserByUsername(username);
+ if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){
+ return jwtTokenUtil.refreshToken(token);
+ }
+ return null;
+ }
+
+ private void authenticateUser(AddUser userDTO) {
+ UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(userDTO.getUsername(), userDTO.getPassword());
+ // 进行安全认证
+ final Authentication authentication = authenticationManager.authenticate(upToken);
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..5335a00
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,80 @@
+server.port= 30000
+
+# JWT
+jwt.header=Authorization
+jwt.secret=8UbBmq9LNnPKFc4sFN7ZF2TTCGbCXTsy
+jwt.expiration=604800
+jwt.tokenHead=Bearer
+jwt.route.authentication.path=auth
+jwt.route.authentication.refresh=refresh
+jwt.route.authentication.register=auth/register
+
+
+# JPA
+spring.jpa.properties.show-sql=true
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.use_sql_comments=true //指出是什么操作生成了该语句
+spring.jpa.show-sql=false
+spring.jpa.generate-ddl=true
+spring.jpa.properties.hibernate.hbm2ddl.auto=update
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
+
+# Security
+spring.security.user.username=admin
+spring.security.user.password=admin
+spring.security.password=admin
+
+
+# Durid
+spring.datasource.sql-script-encoding=utf-8
+spring.datasource.initialization-mode=always
+spring.datasource.druid.driverClassName=com.mysql.jdbc.Driver
+spring.datasource.druid.url=jdbc:mysql://fairy8.cn:3308/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
+spring.datasource.druid.max-open-prepared-statements=25
+spring.datasource.druid.username=test
+spring.datasource.druid.password=newland15%
+spring.datasource.druid.initialSize=5
+spring.datasource.druid.minIdle=1
+spring.datasource.druid.maxActive=50
+spring.datasource.druid.maxWait=60000
+spring.datasource.druid.timeBetweenEvictionRunsMillis=60000
+spring.datasource.druid.minEvictableIdleTimeMillis=300000
+spring.datasource.druid.validationQuery=SELECT 1 FROM DUAL
+spring.datasource.druid.testWhileIdle=true
+spring.datasource.druid.testOnBorrow=false
+spring.datasource.druid.testOnReturn=false
+spring.datasource.druid.poolPreparedStatements=false
+spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize=20
+
+# Druid.Master 监控配置
+spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+spring.datasource.druid.stat-view-servlet.reset-enable=false
+spring.datasource.druid.master.filter.stat.log-slow-sql=true
+spring.datasource.druid.filter.stat.slow-sql-millis=2000
+spring.datasource.druid.filters=stat,wall,slf4j
+#spring.datasource.druid.filters=config,stat,wall,slf4j
+spring.datasource.druid.filter.slf4j.connection-log-enabled=true
+spring.datasource.druid.useGlobalDataSourceStat=true
+spring.datasource.druid.filter.slf4j.enabled=true
+spring.datasource.druid.filter.slf4j.data-source-log-enabled=true
+spring.datasource.druid.filter.slf4j.result-set-log-enabled=true
+spring.datasource.druid.filter.slf4j.statement-parameter-set-log-enabled=true
+spring.datasource.druid.filter.slf4j.statement-parameter-clear-log-enable=true
+spring.datasource.druid.filter.slf4j.statement-create-after-log-enabled=true
+spring.datasource.druid.filter.slf4j.statement-log-enabled=true
+spring.datasource.druid.filter.slf4j.statement-executable-sql-log-enable=true
+spring.datasource.druid.filter.slf4j.statement-execute-after-log-enabled=true
+spring.datasource.druid.filter.slf4j.statement-execute-update-after-log-enabled=true
+spring.datasource.druid.filter.slf4j.statement-execute-batch-after-log-enabled=true
+
+# Logging
+logging.level.root=info
+logging.level.org.springframework=info
+logging.level.org.springframework.jdbc=debug
+logging.level.org.springframework.boot=info
+logging.level.org.mybatis=info
+logging.level.org.hibernate.SQL=debug
+logging.level.com.alibaba.druid=debug
+logging.level.com.github.trang=info
+logging.level.executableSql=debug
+