Bladeren bron

用户登录

tianyabing 2 jaren geleden
bovenliggende
commit
e8bfc6cac7

+ 6 - 0
pom.xml

@@ -78,6 +78,12 @@
             <artifactId>spring-boot-starter-aop</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>4.3.0</version>
+        </dependency>
+
         <!-- redis -->
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 22 - 13
src/main/java/com/sky/ioc/config/GlobalExceptionHandler.java

@@ -1,14 +1,13 @@
 package com.sky.ioc.config;
 
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.exceptions.TokenExpiredException;
+import com.sky.ioc.constant.Constant;
 import com.sky.ioc.tool.ReturnMsg;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 
-import javax.servlet.http.HttpServletRequest;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-
 
 /**
  * @author LunCe
@@ -19,15 +18,25 @@ import java.io.PrintStream;
 @RestControllerAdvice
 public class GlobalExceptionHandler {
 
-//    @ExceptionHandler(Exception.class)
-//    public ReturnMsg exception(Exception e,HttpServletRequest request) {
-//        String requestURI = request.getRequestURI();
-//        StringBuffer requestURL = request.getRequestURL();
-//        // 打印出错误日志
-//        String exceptionAllinformation_01 = getExceptionAllinformation_01(e);
-//        log.error("异常地址'{"+requestURL+"}'","发生异常为:'{"+exceptionAllinformation_01+"'}");
-//        return ReturnMsg.fail();
-//    }
+    @ExceptionHandler(TokenExpiredException.class)
+    public ReturnMsg tokenExpiredException(Exception e) {
+        log.error(e.getMessage());
+        return ReturnMsg.fail(Constant.MSG_CODE.LOGIN_TIMEOUT, "登录失效");
+    }
+
+    @ExceptionHandler(JWTVerificationException.class)
+    public ReturnMsg JWTVerificationException(Exception e) {
+        log.error(e.getMessage());
+        return ReturnMsg.fail(Constant.MSG_CODE.SERVER_ERROR, "请登录后重试");
+    }
+
+    @ExceptionHandler(Exception.class)
+    public ReturnMsg exception(Exception e) {
+        log.error(e.getMessage());
+        return ReturnMsg.fail(e.getMessage());
+    }
+
+
 
 //    public static String getExceptionAllinformation_01(Exception ex) {
 //        ByteArrayOutputStream out = new ByteArrayOutputStream();

+ 45 - 0
src/main/java/com/sky/ioc/config/LoginAspect.java

@@ -0,0 +1,45 @@
+package com.sky.ioc.config;
+
+import com.sky.ioc.constant.Constant;
+import com.sky.ioc.tool.JwtUtil;
+import com.sky.ioc.tool.RedisUtil;
+import com.sky.ioc.tool.ReturnMsg;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+@Slf4j
+@Component
+@Aspect
+public class LoginAspect {
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Around("execution(* com.sky.ioc..*Controller.*(..))")
+    public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
+        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        HttpServletRequest request = sra.getRequest();
+        if (request.getServletPath().contains("login")) {
+            return joinPoint.proceed(joinPoint.getArgs());
+        }
+        String token = request.getHeader("token");
+        if (StringUtils.hasText(token)) {
+            String username = JwtUtil.parseJWT(token) ;
+            Object o = redisUtil.get("login:" + username);
+            if (!Objects.isNull(o)) {
+                return joinPoint.proceed(joinPoint.getArgs());
+            }
+        }
+        return ReturnMsg.fail(Constant.MSG_CODE.LOGIN_TIMEOUT, "当前未登录");
+    }
+}

+ 2 - 0
src/main/java/com/sky/ioc/constant/MsgCode.java

@@ -8,6 +8,8 @@ public class MsgCode {
     public final int NO_PERMISSION = 201;
     /** 参数错误 **/
     public final int PARAM_ERROR = 202;
+
+    public final int LOGIN_TIMEOUT = 203;
     /** 服务端错误 **/
     public final int SERVER_ERROR = 500;
 }

+ 19 - 0
src/main/java/com/sky/ioc/controller/system/UserController.java

@@ -1,5 +1,6 @@
 package com.sky.ioc.controller.system;
 
+import com.sky.ioc.entity.params.system.LoginParam;
 import com.sky.ioc.service.system.UserService;
 import com.sky.ioc.tool.ReturnMsg;
 import io.swagger.annotations.Api;
@@ -21,4 +22,22 @@ public class UserController {
     public ReturnMsg saveCommonMenus(@RequestParam(value = "userID")  long userID,@RequestParam(value = "menuIDs") String menuIDs){
         return userService.updateCommonMenusByUserIdAndMenuId(userID,menuIDs);
     }
+
+    @ApiOperation("系统登录")
+    @PostMapping("/login")
+    public ReturnMsg login(@RequestBody LoginParam loginParam) {
+        return userService.login(loginParam.getUsername(), loginParam.getPassword());
+    }
+
+    @ApiOperation("token 校验")
+    @PostMapping("/validate")
+    public ReturnMsg validate() {
+        return userService.validate();
+    }
+
+    @ApiOperation("注销登录")
+    @PostMapping("/logout")
+    public ReturnMsg logout() {
+        return userService.logout();
+    }
 }

+ 10 - 0
src/main/java/com/sky/ioc/entity/params/system/LoginParam.java

@@ -0,0 +1,10 @@
+package com.sky.ioc.entity.params.system;
+
+import lombok.Data;
+
+@Data
+public class LoginParam {
+
+    private String username;
+    private String password;
+}

+ 39 - 0
src/main/java/com/sky/ioc/entity/result/system/LoginUserVo.java

@@ -0,0 +1,39 @@
+package com.sky.ioc.entity.result.system;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoginUserVo {
+
+    private String id;
+    /** 用户名 */
+    private String userName;
+    /** 头像 */
+    private String photograph;
+    /** 昵称 */
+    private String name;
+    /** 手机号 */
+    private String phone;
+    /** 邮箱 */
+    private String email;
+    /** 单位ID */
+    private String company;
+    /** 部门ID */
+    private String department;
+    /** 在职状态 0-在职 */
+    private String onJobStatus;
+    private String duty;
+    /** 账户状态 0-在职 */
+    private String accountStatus;
+    private String nationality;
+    /** 创建时间 */
+    private String registerTime;
+    /**
+     * 常用功能ID,例如 1,5,6
+     */
+    private  String commonMenus;
+}

+ 6 - 1
src/main/java/com/sky/ioc/service/system/UserService.java

@@ -1,9 +1,14 @@
 package com.sky.ioc.service.system;
 
 import com.sky.ioc.tool.ReturnMsg;
-import org.apache.ibatis.annotations.Param;
 
 public interface UserService {
 
     ReturnMsg updateCommonMenusByUserIdAndMenuId(long userId, String menuIDs);
+
+    ReturnMsg login(String username, String password);
+
+    ReturnMsg logout();
+
+    ReturnMsg validate();
 }

+ 62 - 0
src/main/java/com/sky/ioc/service/system/impl/UserServiceImpl.java

@@ -1,19 +1,81 @@
 package com.sky.ioc.service.system.impl;
 
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.sky.ioc.entity.domain.system.Users;
+import com.sky.ioc.entity.result.system.LoginUserVo;
 import com.sky.ioc.mapper.system.UserMapper;
 import com.sky.ioc.service.system.UserService;
+import com.sky.ioc.tool.JwtUtil;
+import com.sky.ioc.tool.Pbkdf2Sha256Digest;
+import com.sky.ioc.tool.RedisUtil;
 import com.sky.ioc.tool.ReturnMsg;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import java.util.Objects;
 
 @Service
 public class UserServiceImpl implements UserService {
 
     @Autowired
     UserMapper userMapper;
+
+    @Resource
+    private RedisUtil redisUtil;
+
     @Override
     public ReturnMsg updateCommonMenusByUserIdAndMenuId(long userId, String menuIDs) {
         userMapper.updateCommonMenusByUserIdAndMenuId(userId,menuIDs);
        return ReturnMsg.ok();
     }
+
+    @Override
+    public ReturnMsg login(String username, String password) {
+        Users users = userMapper.selectOne(new LambdaQueryWrapper<Users>().eq(Users::getUserName, username));
+        if (Objects.isNull(users)){
+            throw new RuntimeException("用户名或密码错误");
+        }
+        boolean verification = Pbkdf2Sha256Digest.verification(password, users.getPassword());
+        if (!verification){
+            throw new RuntimeException("用户名或密码错误");
+        }
+
+        // 认证成功
+        LoginUserVo loginUser = new LoginUserVo();
+        BeanUtils.copyProperties(users, loginUser);
+
+        String token = JwtUtil.genJwtToken(users);
+
+        // 将用户信息存入redis
+        redisUtil.put("login:"+loginUser.getUserName(), loginUser);
+
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("userInfo", loginUser);
+        jsonObject.put("token", token);
+        return ReturnMsg.ok(jsonObject, "登录成功");
+    }
+
+    @Override
+    public ReturnMsg logout() {
+        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        String token = sra.getRequest().getHeader("token");
+        // 前端注销,后端暂不处理
+        return ReturnMsg.ok("注销成功");
+    }
+
+    @Override
+    public ReturnMsg validate() {
+        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        String token = sra.getRequest().getHeader("token");
+        String username = JwtUtil.parseJWT(token);
+        Users users = userMapper.selectOne(new LambdaQueryWrapper<Users>().eq(Users::getUserName, username));
+        LoginUserVo loginUser = new LoginUserVo();
+        BeanUtils.copyProperties(users, loginUser);
+        return ReturnMsg.ok(loginUser);
+    }
 }

+ 46 - 0
src/main/java/com/sky/ioc/tool/JwtUtil.java

@@ -0,0 +1,46 @@
+package com.sky.ioc.tool;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.sky.ioc.entity.domain.system.Users;
+import org.springframework.beans.factory.annotation.Value;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import java.util.UUID;
+
+public class JwtUtil {
+
+    @Value("${sky.security.key}")
+    private static final String secretKey = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9";
+
+    /**
+     * 生成token
+     *
+     * @param users
+     * @return
+     */
+    public static String genJwtToken(Users users) {
+        String token = JWT.create().withJWTId(UUID.randomUUID().toString()).withAudience("user").withIssuer("sky-ioc-server").withIssuedAt(new Date()).withSubject(users.getUserName()).withClaim("userID", users.getId()).withExpiresAt(Instant.now().plus(16, ChronoUnit.HOURS)).sign(Algorithm.HMAC256(secretKey));
+        return token;
+
+    }
+
+    /**
+     * 解析JWT字符串
+     *
+     * @param token
+     * @return 用户名
+     */
+    public static String parseJWT(String token) {
+        JWTVerifier build = JWT.require(Algorithm.HMAC256(secretKey)).build();
+        DecodedJWT verify = build.verify(token);
+        String username = verify.getSubject();
+        return username;
+    }
+
+}
+

+ 24 - 0
src/main/java/com/sky/ioc/tool/RedisUtil.java

@@ -0,0 +1,24 @@
+package com.sky.ioc.tool;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RedisUtil {
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    public void put(String key , Object object) {
+        redisTemplate.opsForValue().set(key, object);
+    }
+
+    public Object get(String key) {
+        return redisTemplate.opsForValue().get(key);
+    }
+
+    public void delete(String key) {
+        redisTemplate.delete(key);
+    }
+}