Browse Source

finish auth

master
朱天祥 1 year ago
parent
commit
33603e3e3f
24 changed files with 1080 additions and 0 deletions
  1. +33
    -0
      .gitignore
  2. +115
    -0
      pom.xml
  3. +13
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/BookstoreApplication.java
  4. +28
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/component/AppException.java
  5. +18
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/component/Constants.java
  6. +46
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/component/Result.java
  7. +31
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/config/RedisConfig.java
  8. +51
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/config/SecurityConfig.java
  9. +54
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/controller/AuthController.java
  10. +15
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/controller/TestController.java
  11. +46
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/filter/AuthenticationFilter.java
  12. +22
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/handler/AuthenticationEntryPointImpl.java
  13. +24
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/handler/GlobalExceptionHandler.java
  14. +28
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/mapper/UserMapper.java
  15. +53
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/pojo/LoginUser.java
  16. +23
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/pojo/User.java
  17. +26
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/service/UserDetailsServiceImpl.java
  18. +83
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/service/UserService.java
  19. +50
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/utils/JwtUtil.java
  20. +103
    -0
      src/main/java/cn/edu/ecnu/stu/bookstore/utils/RequestUtil.java
  21. +18
    -0
      src/main/resources/application.yml
  22. +22
    -0
      src/main/resources/mapper/UserMapper.xml
  23. +28
    -0
      src/test/java/cn/edu/ecnu/stu/bookstore/BookstoreApplicationTests.java
  24. +150
    -0
      src/test/java/cn/edu/ecnu/stu/bookstore/RegisterTest.java

+ 33
- 0
.gitignore View File

@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

+ 115
- 0
pom.xml View File

@ -0,0 +1,115 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.edu.ecnu.stu</groupId>
<artifactId>bookstore</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>bookstore</name>
<description>bookstore</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>cn.edu.ecnu.stu.bookstore.BookstoreApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

+ 13
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/BookstoreApplication.java View File

@ -0,0 +1,13 @@
package cn.edu.ecnu.stu.bookstore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BookstoreApplication {
public static void main(String[] args) {
SpringApplication.run(BookstoreApplication.class, args);
}
}

+ 28
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/component/AppException.java View File

@ -0,0 +1,28 @@
package cn.edu.ecnu.stu.bookstore.component;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class AppException extends RuntimeException{
private String code;
private String message;
public void setCode(String code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}

+ 18
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/component/Constants.java View File

@ -0,0 +1,18 @@
package cn.edu.ecnu.stu.bookstore.component;
public interface Constants {
String SYSTEM_ERROR = "500";
String CLIENT_ERROR = "400";
String SUCCESS = "200";
String AUTHENTICATION_ERROR = "401";
String UNAUTHORIZED_ERROR = "403";
String REGISTER_ERROR_MESSAGE = "用户名已存在";
String PARAMETER_ERROR_MESSAGE = "参数非法";
String SUCCESS_MESSAGE = "ok";
String AUTHENTICATION_ERROR_MESSAGE = "用户未认证或token过期,请先登录";
String PASSWORD_ERROR = "用户名不存在或密码错误";
String URL_PREFIX = "http://127.0.0.1:8080";
}

+ 46
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/component/Result.java View File

@ -0,0 +1,46 @@
package cn.edu.ecnu.stu.bookstore.component;
import lombok.Data;
@Data
public class Result {
private Object data;
private String message;
private String code;
public Result(String code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
@Override
public String toString() {
return "Result{" +
"data=" + data +
", message='" + message + '\'' +
", code='" + code + '\'' +
'}';
}
public static Result success(Object data) {
return new Result(Constants.SUCCESS, "ok", data);
}
public static Result error(String code, String message) {
return new Result(code, message, null);
}
public static Result error(String code, String message, Object data) {
return new Result(code, message, data);
}
public static Result success() {
return new Result(Constants.SUCCESS, Constants.SUCCESS_MESSAGE, null);
}
}

+ 31
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/config/RedisConfig.java View File

@ -0,0 +1,31 @@
package cn.edu.ecnu.stu.bookstore.config;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig implements InitializingBean {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Override
public void afterPropertiesSet() throws Exception {
RedisSerializer stringSerializer = new StringRedisSerializer();
//key序列化方式
redisTemplate.setKeySerializer(stringSerializer);
//String的序列化方式
redisTemplate.setStringSerializer(stringSerializer);
//value序列化方式
redisTemplate.setValueSerializer(stringSerializer);
//hash key序列化方式
redisTemplate.setHashKeySerializer(stringSerializer);
//hash value序列化方式
redisTemplate.setHashValueSerializer(stringSerializer);
}
}

+ 51
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/config/SecurityConfig.java View File

@ -0,0 +1,51 @@
package cn.edu.ecnu.stu.bookstore.config;
import cn.edu.ecnu.stu.bookstore.filter.AuthenticationFilter;
import cn.edu.ecnu.stu.bookstore.handler.AuthenticationEntryPointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public AuthenticationFilter authenticationFilter;
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPointImpl();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/auth/*").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
}
}

+ 54
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/controller/AuthController.java View File

@ -0,0 +1,54 @@
package cn.edu.ecnu.stu.bookstore.controller;
import cn.edu.ecnu.stu.bookstore.component.Result;
import cn.edu.ecnu.stu.bookstore.pojo.User;
import cn.edu.ecnu.stu.bookstore.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/register")
public Result register(@RequestBody User user) {
userService.register(user);
return Result.success();
}
@PostMapping("/unregister")
public Result unregister(@RequestBody User user) {
userService.unregister(user);
return Result.success();
}
@PostMapping("/login")
public Result login(@RequestBody User user) {
String token = userService.login(user);
HashMap<String, Object> map = new HashMap<>();
map.put("token", token);
return Result.success(map);
}
@PostMapping("/password")
public Result changePassword(@RequestBody Map<String, String> map) {
String username = map.get("username");
String oldPassword = map.get("oldPassword");
String newPassword = map.get("newPassword");
userService.changePassword(username, oldPassword, newPassword);
return Result.success();
}
@PostMapping("/logout")
public Result logout(@RequestBody Map<String, String> map) {
userService.logout(map.get("username"));
return Result.success();
}
}

+ 15
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/controller/TestController.java View File

@ -0,0 +1,15 @@
package cn.edu.ecnu.stu.bookstore.controller;
import cn.edu.ecnu.stu.bookstore.component.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/test")
public Result test() {
return Result.success("hello, test");
}
}

+ 46
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/filter/AuthenticationFilter.java View File

@ -0,0 +1,46 @@
package cn.edu.ecnu.stu.bookstore.filter;
import cn.edu.ecnu.stu.bookstore.pojo.User;
import cn.edu.ecnu.stu.bookstore.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthenticationFilter extends OncePerRequestFilter {
@Autowired
private RedisTemplate redisTemplate;
private boolean hasLogin(Integer userId) {
String s = (String)redisTemplate.opsForValue().get("userId:" + userId);
return StringUtils.hasText(s);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("token");
if(!StringUtils.hasText(token)){
filterChain.doFilter(request, response);
return;
}
User user = (User) JwtUtil.getTokenInfo(token, User.class);
if(!hasLogin(user.getId())) {
filterChain.doFilter(request, response);
return;
}
UsernamePasswordAuthenticationToken token1 = new UsernamePasswordAuthenticationToken(user, null, null);
SecurityContextHolder.getContext().setAuthentication(token1);
filterChain.doFilter(request, response);
}
}

+ 22
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/handler/AuthenticationEntryPointImpl.java View File

@ -0,0 +1,22 @@
package cn.edu.ecnu.stu.bookstore.handler;
import cn.edu.ecnu.stu.bookstore.component.Constants;
import cn.edu.ecnu.stu.bookstore.component.Result;
import com.alibaba.fastjson.JSON;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(JSON.toJSONString(Result.error(Constants.AUTHENTICATION_ERROR, Constants.AUTHENTICATION_ERROR_MESSAGE)));
}
}

+ 24
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/handler/GlobalExceptionHandler.java View File

@ -0,0 +1,24 @@
package cn.edu.ecnu.stu.bookstore.handler;
import cn.edu.ecnu.stu.bookstore.component.AppException;
import cn.edu.ecnu.stu.bookstore.component.Constants;
import cn.edu.ecnu.stu.bookstore.component.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(AppException.class)
public Result handleAppException(AppException e) {
return Result.error(e.getCode(), e.getMessage());
}
// @ExceptionHandler(Exception.class)
// public Result handleException(Exception e) {
// return Result.error(Constants.SYSTEM_ERROR, e.getMessage());
// }
}

+ 28
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/mapper/UserMapper.java View File

@ -0,0 +1,28 @@
package cn.edu.ecnu.stu.bookstore.mapper;
import cn.edu.ecnu.stu.bookstore.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface UserMapper {
int insert(@Param("user") User user);
int delete(@Param("userId") int userId);
int checkUserByUsername(@Param("username") String username);
int deleteByName(@Param("username") String username);
@Select("select id, username, password, address, phone from t_user where username = #{username}")
User selectOneByName(@Param("username") String username);
@Select("select count(*) from t_user where username = #{username} and password = #{password}")
int checkPassword(@Param("username") String username, @Param("password") String password);
@Update("update t_user set password = #{password} where username = #{username}")
int updatePassword(@Param("username") String username, @Param("password") String password);
}

+ 53
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/pojo/LoginUser.java View File

@ -0,0 +1,53 @@
package cn.edu.ecnu.stu.bookstore.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serializable;
import java.util.Collection;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {
private User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

+ 23
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/pojo/User.java View File

@ -0,0 +1,23 @@
package cn.edu.ecnu.stu.bookstore.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private int id;
private String username;
private String password;
private int balance;
private String phone;
private String address;
}

+ 26
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/service/UserDetailsServiceImpl.java View File

@ -0,0 +1,26 @@
package cn.edu.ecnu.stu.bookstore.service;
import cn.edu.ecnu.stu.bookstore.component.AppException;
import cn.edu.ecnu.stu.bookstore.component.Constants;
import cn.edu.ecnu.stu.bookstore.pojo.LoginUser;
import cn.edu.ecnu.stu.bookstore.pojo.User;
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;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.selectUserByName(username);
if(user == null)
throw new AppException(Constants.CLIENT_ERROR, Constants.PARAMETER_ERROR_MESSAGE);
return new LoginUser(user);
}
}

+ 83
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/service/UserService.java View File

@ -0,0 +1,83 @@
package cn.edu.ecnu.stu.bookstore.service;
import cn.edu.ecnu.stu.bookstore.component.AppException;
import cn.edu.ecnu.stu.bookstore.component.Constants;
import cn.edu.ecnu.stu.bookstore.mapper.UserMapper;
import cn.edu.ecnu.stu.bookstore.pojo.LoginUser;
import cn.edu.ecnu.stu.bookstore.pojo.User;
import cn.edu.ecnu.stu.bookstore.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private RedisTemplate redisTemplate;
public void register(User user) {
if(!StringUtils.hasLength(user.getUsername()))
throw new AppException(Constants.CLIENT_ERROR, Constants.PARAMETER_ERROR_MESSAGE);
if(userMapper.checkUserByUsername(user.getUsername()) != 0)
throw new AppException(Constants.CLIENT_ERROR, Constants.REGISTER_ERROR_MESSAGE);
String encoded = passwordEncoder.encode(user.getPassword());
user.setPassword(encoded);
userMapper.insert(user);
}
public void unregister(User user) {
User user1 = userMapper.selectOneByName(user.getUsername());
if(user1 == null || !passwordEncoder.matches(user.getPassword(), user1.getPassword())) {
throw new AppException(Constants.CLIENT_ERROR, Constants.PASSWORD_ERROR);
}
userMapper.deleteByName(user.getUsername());
}
public User selectUserByName(String username) {
return userMapper.selectOneByName(username);
}
public String login(User user) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
Authentication authenticate = authenticationManager.authenticate(token);
LoginUser loginUser = (LoginUser)authenticate.getPrincipal();
redisTemplate.opsForValue().set("userId:" + loginUser.getUser().getId(), "1", 1, TimeUnit.DAYS);
return JwtUtil.getToken(loginUser.getUser());
}
public void logout(String username) {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if(!user.getUsername().equals(username)) {
throw new AppException(Constants.CLIENT_ERROR, Constants.PARAMETER_ERROR_MESSAGE);
}
redisTemplate.delete("userId:" + user.getId());
}
public void changePassword(String username, String oldPassword, String newPassword) {
User user = userMapper.selectOneByName(username);
if(user == null || !passwordEncoder.matches(oldPassword, user.getPassword())){
throw new AppException(Constants.CLIENT_ERROR, Constants.PASSWORD_ERROR);
}
newPassword = passwordEncoder.encode(newPassword);
userMapper.updatePassword(username, newPassword);
redisTemplate.delete("userId:" + user.getId());
}
}

+ 50
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/utils/JwtUtil.java View File

@ -0,0 +1,50 @@
package cn.edu.ecnu.stu.bookstore.utils;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
@Component
public class JwtUtil {
/** 盐值*/
private static final String SING="!@#%^$*$%#^$#%^%$$#QWBADasda881";
//生成令牌
public static String getToken(Object object){
//获取日历对象
Calendar calendar= Calendar.getInstance();
//默认1天过期
calendar.add(Calendar.DATE,1);
//新建一个JWT的Builder对象
JWTCreator.Builder builder = JWT.create();
String jsonStr = JSON.toJSONString(object);
builder.withClaim("data",jsonStr);
//设置过期时间和签名
return builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SING));
}
/**
* 验签并返回DecodedJWT
* @param token 令牌
*/
public static Object getTokenInfo(String token,Class<?> clazz){
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
return JSON.parseObject(jwt.getClaim("data").asString(), clazz);
}
public static Date getTokenExpiration(String token) {
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
return jwt.getExpiresAt();
}
}

+ 103
- 0
src/main/java/cn/edu/ecnu/stu/bookstore/utils/RequestUtil.java View File

@ -0,0 +1,103 @@
package cn.edu.ecnu.stu.bookstore.utils;
import cn.edu.ecnu.stu.bookstore.component.Result;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class RequestUtil {
public static Result post(String url, Map<String, Object> bodyMap, String token) {
// post请求
HttpClient httpClient;
HttpPost httpPost;
HttpResponse response;
String responseContent;
String body = bodyMap == null ? null : JSON.toJSONString(bodyMap);
try {
// 创建 httpClient
httpClient = HttpClients.createDefault();
httpPost = new HttpPost(url);
httpPost.addHeader("Accept", "*/*");
httpPost.addHeader("Content-Type", "application/json;charset=utf8");
if(token != null)
httpPost.addHeader("token", token);
// set entity
if(body != null)
httpPost.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
// 发送请求
response = httpClient.execute(httpPost);
// 得到响应
HttpEntity httpEntity = response.getEntity();
responseContent = EntityUtils.toString(httpEntity, "UTF-8");
// 释放资源
EntityUtils.consume(httpEntity);
return JSON.parseObject(responseContent, Result.class);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Result get(String url, Map<String, Object> params, String token) {
// post请求
HttpClient httpClient;
HttpGet httpGet;
HttpResponse response;
String responseContent;
try {
// 创建 httpClient
httpClient = HttpClients.createDefault();
httpGet = new HttpGet(url);
httpGet.addHeader("Accept", "*/*");
httpGet.addHeader("Content-Type", "application/json;charset=utf8");
if(token != null)
httpGet.addHeader("token", token);
// set params
if(params != null) {
BasicHttpParams httpParams = new BasicHttpParams();
for (Map.Entry<String, Object> entry : params.entrySet()) {
httpParams.setParameter(entry.getKey(), entry.getValue());
}
httpGet.setParams(httpParams);
}
// 发送请求
response = httpClient.execute(httpGet);
// 得到响应
HttpEntity httpEntity = response.getEntity();
responseContent = EntityUtils.toString(httpEntity, "UTF-8");
// 释放资源
EntityUtils.consume(httpEntity);
return JSON.parseObject(responseContent, Result.class);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

+ 18
- 0
src/main/resources/application.yml View File

@ -0,0 +1,18 @@
server:
port: 8080
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: cn.edu.ecnu.stu.bookstore.pojo
spring:
datasource:
url: jdbc:mysql://localhost:3306/bookstore?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username: root
password: qwe030318
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
redis:
host: 106.75.115.165
port: 6379
password: qwe030318

+ 22
- 0
src/main/resources/mapper/UserMapper.xml View File

@ -0,0 +1,22 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.edu.ecnu.stu.bookstore.mapper.UserMapper">
<insert id="insert" useGeneratedKeys="true">
insert into t_user(username, password, balance, address, phone)
values (#{user.username}, #{user.password}, #{user.balance}, #{user.address}, #{user.phone})
</insert>
<delete id="delete">
delete from t_user where id = #{userId}
</delete>
<delete id="deleteByName">
delete from t_user where username = #{username}
</delete>
<select id="checkUserByUsername" resultType="integer">
select count(*) from t_user where username = #{username}
</select>
</mapper>

+ 28
- 0
src/test/java/cn/edu/ecnu/stu/bookstore/BookstoreApplicationTests.java View File

@ -0,0 +1,28 @@
package cn.edu.ecnu.stu.bookstore;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
class BookstoreApplicationTests {
@Test
void contextLoads() {
}
@Test
public void SetTest(@Autowired RedisTemplate redisTemplate){
ValueOperations value = redisTemplate.opsForValue();
value.set("springBoot","RedisOnSpringBoot");
}
@Test
public void GetTest(@Autowired RedisTemplate redisTemplate){
ValueOperations value = redisTemplate.opsForValue();
Object o = value.get("springBoot");
System.out.println(o);
}
}

+ 150
- 0
src/test/java/cn/edu/ecnu/stu/bookstore/RegisterTest.java View File

@ -0,0 +1,150 @@
package cn.edu.ecnu.stu.bookstore;
import cn.edu.ecnu.stu.bookstore.component.Constants;
import cn.edu.ecnu.stu.bookstore.component.Result;
import cn.edu.ecnu.stu.bookstore.utils.RequestUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.http.ResponseUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
@SpringBootTest
public class RegisterTest {
@Test
public void testRegister() {
String url = Constants.URL_PREFIX + "/auth/register";
Map<String, Object> map = new HashMap<>();
String username = UUID.randomUUID().toString();
String password = username + "x";
map.put("username", username);
map.put("password", password);
Result result = RequestUtil.post(url, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
map.put("username", username);
result = RequestUtil.post(url, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.CLIENT_ERROR);
}
@Test
public void testLogin() {
String url = Constants.URL_PREFIX + "/auth/register";
Map<String, Object> map = new HashMap<>();
String username = UUID.randomUUID().toString();
String password = username + "x";
map.put("username", username);
map.put("password", password);
Result result = RequestUtil.post(url, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
url = Constants.URL_PREFIX + "/auth/login";
result = RequestUtil.post(url, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
map.put("password", password + "x");
result = RequestUtil.post(url, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SYSTEM_ERROR);
}
@Test
public void testUnregister() {
String registerUrl = Constants.URL_PREFIX + "/auth/register";
Map<String, Object> map = new HashMap<>();
String username = UUID.randomUUID().toString();
String password = username + "x";
map.put("username", username);
map.put("password", password);
Result result = RequestUtil.post(registerUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
String loginUrl = Constants.URL_PREFIX + "/auth/login";
result = RequestUtil.post(loginUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
String unregisterUrl = Constants.URL_PREFIX + "/auth/unregister";
result = RequestUtil.post(unregisterUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
result = RequestUtil.post(loginUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.CLIENT_ERROR);
}
@Test
public void testLogout() {
String registerUrl = Constants.URL_PREFIX + "/auth/register";
Map<String, Object> map = new HashMap<>();
String username = UUID.randomUUID().toString();
String password = username + "x";
map.put("username", username);
map.put("password", password);
Result result = RequestUtil.post(registerUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
String loginUrl = Constants.URL_PREFIX + "/auth/login";
result = RequestUtil.post(loginUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
JSONObject data = (JSONObject) result.getData();
String token = data.getString("token");
String testUrl = Constants.URL_PREFIX + "/test";
result = RequestUtil.get(testUrl, null, token);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
String logoutUrl = Constants.URL_PREFIX + "/auth/logout";
result = RequestUtil.post(logoutUrl, map, token);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
result = RequestUtil.get(testUrl, null, token);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.AUTHENTICATION_ERROR);
}
@Test
public void testPassword() {
String registerUrl = Constants.URL_PREFIX + "/auth/register";
Map<String, Object> map = new HashMap<>();
String username = UUID.randomUUID().toString();
String password = username + "x";
map.put("username", username);
map.put("password", password);
Result result = RequestUtil.post(registerUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
String newPassword = password + "x";
map.put("oldPassword", password);
map.put("newPassword", newPassword);
String passwordUrl = Constants.URL_PREFIX + "/auth/password";
result = RequestUtil.post(passwordUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
map.put("password", newPassword);
String loginUrl = Constants.URL_PREFIX + "/auth/login";
result = RequestUtil.post(loginUrl, map, null);
assert result != null && result.getCode() != null && result.getCode().equals(Constants.SUCCESS);
}
}

Loading…
Cancel
Save