jinlin
2024-02-26 6f0714843341b168573ad0272069f7af2d3d2b87
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
 * Copyright (c) 2018 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
 
package com.zt.security.controller;
 
import com.sun.deploy.net.URLEncoder;
import com.zt.common.exception.ErrorCode;
import com.zt.common.exception.RenException;
import com.zt.common.servlet.Result;
import com.zt.common.utils.IpUtils;
import com.zt.core.context.User;
import com.zt.core.context.UserContext;
import com.zt.core.sys.model.SysUser;
import com.zt.modules.log.enums.LoginOperationEnum;
import com.zt.modules.log.enums.LoginStatusEnum;
import com.zt.modules.log.model.SysLogLogin;
import com.zt.modules.log.service.SysLogLoginService;
import com.zt.modules.sys.enums.UserStatus;
import com.zt.modules.sys.service.SysUserService;
import com.zt.security.dto.LoginExDto;
import com.zt.security.service.SysUserTokenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
 
/**
 * CAS 集成登录
 *
 * @author hanjing
 */
@RestController
@Api(tags = "CAS 集成登录")
public class CasSsoController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserTokenService sysUserTokenService;
    @Autowired
    private SysLogLoginService sysLogLoginService;
 
    @PostMapping("public/casauth")
    @ApiOperation(value = "CAS 集成登录,验证用户信息。")
    public Result casAuth(HttpServletRequest request, @RequestBody LoginExDto login) {
 
        String username = "";
        String ssoToken = login.getSsoToken();
        try{
            String password = "Edj&3G0L#sD"; // sso token 解密密钥,若修改此变量值,请对应修改 cas-client\src\main\webapp\index.jsp 中对应的变量值
            byte[] res = new BASE64Decoder().decodeBuffer(ssoToken);
            byte[] decrypt = decrypt(res, password);
            ssoToken = URLDecoder.decode(new String(decrypt,"utf-8"), "UTF-8");
 
            // 分隔 token 数据(用户名|#|创建登录跳转时的时间戳)
            String[] prams = ssoToken.split("\\|#\\|");
            username = prams[0];
            long create_time = Long.parseLong(prams[1]);
            long current_time = System.currentTimeMillis();
            // 当前时间比ssoToken创建时间大于1分钟,则认为token无效,需要重新登录。
            if(current_time - create_time > 2 * 60 * 1000){
                throw new RenException(ErrorCode.TOKEN_INVALID);
            }
        }catch (Exception e){
            // 抛出异常,token 无效。
            throw new RenException(ErrorCode.TOKEN_INVALID);
        }
 
        // 用户信息
        SysUser user = sysUserService.getByUsername(username);
 
        SysLogLogin log = new SysLogLogin();
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));
 
        // 用户不存在
        if (user == null) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(login.getSsoToken());
            sysLogLoginService.insert(log);
 
            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }
 
        // 账号停用
        if (user.getStatus() == UserStatus.DISABLE.getValue()) {
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.insert(log);
 
            throw new RenException(ErrorCode.ACCOUNT_DISABLE);
        }
 
        // 登录成功
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        sysLogLoginService.insert(log);
 
        return sysUserTokenService.createToken(user.getId(), "", ssoToken);
    }
 
    /**
     * AES加密字符串
     *
     * @param content
     *            需要被加密的字符串
     * @param password
     *            加密需要的密码
     * @return 密文
     */
    public static byte[] encrypt(String content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
            kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
            //加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
            SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
            byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
            byte[] result = cipher.doFinal(byteContent);// 加密
            return result;
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 解密AES加密过的字符串
     *
     * @param content
     *            AES加密过过的内容
     * @param password
     *            加密时的密码
     * @return 明文
     */
    private static byte[] decrypt(byte[] content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
            kgen.init(128, new SecureRandom(password.getBytes()));
            SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
            byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, key);// 初始化为解密模式的密码器
            byte[] result = cipher.doFinal(content);
            return result; // 明文
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }
}