kongzy
2024-07-12 28aaf2ffa1dbb860a292ba330a7e9362e60e7832
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package com.gkhy.assess.framework.shiro.service;
 
import com.gkhy.assess.common.constant.CacheConstant;
import com.gkhy.assess.common.enums.ApproveStatusEnum;
import com.gkhy.assess.common.enums.UserIdentityEnum;
import com.gkhy.assess.common.enums.UserStatusEnum;
import com.gkhy.assess.common.utils.JwtTokenUtil;
import com.gkhy.assess.common.utils.RedisUtils;
import com.gkhy.assess.system.domain.SysUser;
import com.gkhy.assess.system.service.SysUserService;
import com.gkhy.assess.system.utils.ShiroUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
 
@Component
public class SysLoginService  {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysPasswordService passwordService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private HttpServletRequest request;
 
    public SysUser login(String username, String password,Integer identity) {
        SysUser sysUser=sysUserService.getUserByUsernamePhone(username,identity);
        validUser(sysUser);
        passwordService.validate(sysUser,password);
        recordLoginInfo(sysUser.getId());
        return sysUser;
    }
 
    public void validUser(SysUser sysUser){
        if(sysUser==null) {
            throw new AuthenticationException("用户不存在");
        }
        String uri=request.getRequestURI();
        if(uri.startsWith("/api/system")){
            if(UserIdentityEnum.EXPERT.getCode().equals(sysUser.getIdentity())){
                throw new AuthenticationException("专家用户无权登录后台");
            }
        }else if(uri.startsWith("/api/app/")){
            if(!UserIdentityEnum.EXPERT.getCode().equals(sysUser.getIdentity())){
                throw new AuthenticationException("只有专家用户才能登录APP");
            }
        }
        if(UserStatusEnum.DELETED.getCode().equals(sysUser.getDelFlag())){
            throw new AuthenticationException("用户已被删除");
        }
        if(UserStatusEnum.DISABLE.getCode().equals(sysUser.getStatus())){
            throw new AuthenticationException("用户已被停用");
        }
//        if(UserIdentityEnum.AGENCY.getCode().equals(sysUser.getIdentity())){
//            if(!ApproveStatusEnum.APPROVED.getCode().equals(sysUser.getState())){
//                throw new AuthenticationException("机构账户审批还未通过");
//            }
//        }
    }
 
    public SysUser validJwtToken(String jwtToken){
 
        String username= JwtTokenUtil.getUsername(jwtToken);
        Integer identity=JwtTokenUtil.getIdentity(jwtToken);
        if(StringUtils.isEmpty(username)||identity==null){
            throw new AuthenticationException("token非法无效!");
        }
        SysUser sysUser=sysUserService.getUserByUsernamePhone(username,identity);
        validUser(sysUser);
        if(!JwtTokenUtil.verify(jwtToken,username,sysUser.getPassword(),identity)){
            throw new AuthenticationException("token非法无效!");
        }
        if(!jwtTokenRefresh(jwtToken,username,sysUser.getPassword(),identity)){
            throw new AuthenticationException("您的账号登录过期,请重新登录!");
        }
     //   setRolePermission(sysUser);
        return sysUser;
    }
 
    /**
     * JWTToken刷新生命周期 (实现: 用户在线操作不掉线功能)
     * 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样),缓存有效期设置为Jwt有效时间的2倍
     * 2、当该用户再次请求时,通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证
     * 3、当该用户这次请求jwt生成的token值已经超时,但该token对应cache中的k还是存在,则表示该用户一直在操作只是JWT的token失效了,程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值,该缓存生命周期重新计算
     * 4、当该用户这次请求jwt在生成的token值已经超时,并在cache中不存在对应的k,则表示该用户账户空闲超时,返回用户信息已失效,请重新登录。
     * 注意: 前端请求Header中设置Authorization保持不变,校验有效性以缓存中的token为准。
     *       用户过期时间 = Jwt有效时间 * 2。
     *
     * @param username
     * @param passWord
     * @return
     */
    public boolean jwtTokenRefresh(String jwtToken, String username, String passWord, Integer identity){
        String tokenKey=redisUtils.generateKey(CacheConstant.SYS_USER_TOKEN+":"+JwtTokenUtil.md5Encode(jwtToken));
      //  String userKey=redisUtils.generateKey(CacheConstant.SYS_USER_TOKEN+":"+username+"_"+identity);
        String cacheToken= (String) redisUtils.get(tokenKey);
        if(StringUtils.isNotEmpty(cacheToken)){
            // 校验token有效性
            if(!JwtTokenUtil.isNeedUpdate(cacheToken,username,passWord,identity)){
                String newToken=JwtTokenUtil.sign(username,passWord,identity);
                // 设置超时时间
                redisUtils.set(tokenKey,newToken,JwtTokenUtil.EXPIRATION*2/1000);
               // redisUtils.expire(userKey,(JwtTokenUtil.EXPIRATION*2/1000)+2);
            }
            return true;
        }
        return false;
    }
 
 
    public void recordLoginInfo(Long userId){
        SysUser user=new SysUser();
        user.setId(userId);
        user.setLoginIp(ShiroUtils.getIp());
        user.setLoginDate(LocalDateTime.now());
        sysUserService.updateById(user);
 
    }
}