first commit

This commit is contained in:
2019-05-23 17:46:46 +08:00
parent 2586bdb9d3
commit 54ecf61073
47 changed files with 2223 additions and 0 deletions
+206
View File
@@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>net.alawn</groupId>
<artifactId>bill</artifactId>
<packaging>war</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>bill</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<h2.version>1.4.197</h2.version>
<mysql.version>5.1.46</mysql.version>
<druid.version>1.1.16</druid.version>
<swagger2.version>2.8.0</swagger2.version>
<mybatis-spring-boot-starter.version>2.0.0</mybatis-spring-boot-starter.version>
<lombok.version>1.18.8</lombok.version>
<springboot.version>2.1.5.RELEASE</springboot.version>
<commons-lang3.version>3.7</commons-lang3.version>
<fastjson.version>1.2.54</fastjson.version>
<commons-io.version>2.6</commons-io.version>
<junit.version>4.12</junit.version>
<jjwt.version>0.10.5</jjwt.version>
</properties>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>io.jsonwebtoken</groupId>-->
<!-- <artifactId>jjwt</artifactId>-->
<!-- <version>0.9.1</version>-->
<!-- </dependency>-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>com.h2database</groupId> -->
<!-- <artifactId>h2</artifactId> -->
<!-- <version>${h2.version}</version> -->
<!-- </dependency> -->
<!-- <dependency>-->
<!-- <groupId>org.hibernate</groupId>-->
<!-- <artifactId>hibernate-ehcache</artifactId>-->
<!-- <version>${hibernate.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.hibernate</groupId>-->
<!-- <artifactId>hibernate-entitymanager</artifactId>-->
<!-- <version>${hibernate-entitymanager.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.alibaba</groupId>-->
<!-- <artifactId>druid</artifactId>-->
<!-- <version>${druid.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${springboot.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.hibernate.javax.persistence</groupId>-->
<!-- <artifactId>hibernate-jpa-2.1-api</artifactId>-->
<!-- <version>${hibernate-jpa-api.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.data</groupId>-->
<!-- <artifactId>spring-data-jpa</artifactId>-->
<!-- <version>${spring-data-jpa.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-tomcat</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${springboot.version}</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<skip>true</skip>
<includes>
<include>${project.basedir}/src/test/java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -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);
}
}
@@ -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<ApiKey> securitySchemes() {
return newArrayList(
new ApiKey("Authorization", "Authorization", "header"));
}
private List<SecurityContext> securityContexts() {
return newArrayList(
SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build()
);
}
List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return newArrayList(
new SecurityReference("Authorization", authorizationScopes));
}
}
@@ -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<String> {
@Override
public Optional<String> 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();
}
}
}
@@ -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);
}
}
@@ -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<Post> 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<Post> getPost(@PathVariable long id){
log.info("post id:" + id);
/** 登记 Post */
Optional<Post> 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<Merchant> 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<Merchant> getMerchant(@PathVariable long id){
/** 登记 Post */
Optional<Merchant> 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<Title> 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<Title> getTitle(@PathVariable long id){
/** 登记 Post */
Optional<Title> title = titleRepo.findById(id);
if(title.isPresent()) {
return ResponseEntity.ok(title.get());
}
else{
return ResponseEntity.noContent().build();
}
}
}
@@ -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<Book> 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<Item> 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);
}
}
@@ -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<BillItem> billItems;
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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 ;
}
@@ -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;
}
@@ -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<Authority> 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<GrantedAuthority> mapToGrantedAuthorities(Set<Authority> authorities) {
//// return authorities.stream()
//// .map(authority -> new SimpleGrantedAuthority(authority.getId().getAuthority()))
//// .collect(Collectors.toSet());
//// }
// private static Set<GrantedAuthority> mapToGrantedAuthorities(Set<Authority> 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());
// }
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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; }
}
@@ -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 = "业务成功" ;
}
@@ -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);
}
}
@@ -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<Authority, AuthorityId> {
}
@@ -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<Book, Long> {
}
@@ -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<Item, Long> {
}
@@ -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<Merchant, Long> {
}
@@ -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<Post, Long> {
}
@@ -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<Title, Long> {
}
@@ -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, String> {
User findByUsername(String username);
}
@@ -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;
}
}
@@ -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);
}
}
}
@@ -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");
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
String generateToken(Map<String, Object> 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;
}
}
@@ -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<GrantedAuthority> mapToGrantedAuthorities(Set<Authority> authorities) {
return authorities.stream()
.map(authority -> new SimpleGrantedAuthority(authority.getId().getAuthority()))
.collect(Collectors.toSet());
}
// private static List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) {
// return authorities.stream()
// .map(SimpleGrantedAuthority::new)
// .collect(Collectors.toList());
// }
}
@@ -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));
// }
}
@@ -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);
}
@@ -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);
}
}
+80
View File
@@ -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