Files
pqs/pqs-auth/src/main/java/com/njcn/auth/controller/AuthController.java
chendaofei 59b56a39dc 1.用能代码提交
2.系统并发bug修改
2024-07-29 13:56:28 +08:00

206 lines
9.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.njcn.auth.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.njcn.auth.service.UserTokenService;
import com.njcn.auth.utils.AuthPubUtil;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.constant.SecurityConstants;
import com.njcn.common.pojo.dto.UserTokenInfo;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import com.njcn.common.utils.LogUtil;
import com.njcn.common.utils.sm.DesUtils;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.user.api.PassWordRuleFeugnClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.enums.UserResponseEnum;
import com.njcn.user.pojo.po.UserStrategy;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.RequestUtil;
import com.njcn.web.utils.RestTemplateUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
import springfox.documentation.annotations.ApiIgnore;
import java.net.URI;
import java.security.KeyPair;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author hongawen
*/
@Api(tags = "认证中心")
@Slf4j
@RestController
@RequestMapping("/oauth")
@AllArgsConstructor
public class AuthController extends BaseController {
private final TokenEndpoint tokenEndpoint;
private final KeyPair keyPair;
private final RedisUtil redisUtil;
private final UserFeignClient userFeignClient;
private final PassWordRuleFeugnClient passWordRuleFeugnClient;
private final UserTokenService userTokenService;
@ApiIgnore
@OperateInfo(info = LogEnum.SYSTEM_SERIOUS, operateType = OperateType.AUTHENTICATE)
@ApiOperation("登录认证")
@ApiImplicitParams({
@ApiImplicitParam(name = SecurityConstants.GRANT_TYPE, defaultValue = "password", value = "授权模式", required = true),
@ApiImplicitParam(name = SecurityConstants.CLIENT_ID, defaultValue = "njcn", value = "Oauth2客户端ID", required = true),
@ApiImplicitParam(name = SecurityConstants.CLIENT_SECRET, defaultValue = "njcnpqs", value = "Oauth2客户端秘钥", required = true),
@ApiImplicitParam(name = SecurityConstants.REFRESH_TOKEN, value = "刷新token"),
@ApiImplicitParam(name = SecurityConstants.USERNAME, value = "登录用户名"),
@ApiImplicitParam(name = SecurityConstants.PASSWORD, value = "登录密码"),
@ApiImplicitParam(name = SecurityConstants.IMAGE_CODE, value = "图形验证码"),
@ApiImplicitParam(name = SecurityConstants.PHONE, value = "手机号"),
@ApiImplicitParam(name = SecurityConstants.SMS_CODE, value = "短信验证码"),
})
@PostMapping("/token")
public Object postAccessToken(@ApiIgnore Principal principal, @RequestParam @ApiIgnore Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
String methodDescribe = getMethodDescribe("postAccessToken");
String username = parameters.get(SecurityConstants.USERNAME);
String grantType = parameters.get(SecurityConstants.GRANT_TYPE);
if (grantType.equalsIgnoreCase(SecurityConstants.GRANT_CAPTCHA) || grantType.equalsIgnoreCase(SecurityConstants.REFRESH_TOKEN_KEY)) {
username = DesUtils.aesDecrypt(username);
} else if (grantType.equalsIgnoreCase(SecurityConstants.GRANT_SMS_CODE)) {
//短信方式登录,将手机号赋值为用户名
username = parameters.get(SecurityConstants.PHONE);
}
//判断当前登录是否超过最大并发数
UserStrategy data = passWordRuleFeugnClient.getUserStrategy().getData();
String onlineUserKey = SecurityConstants.TOKEN_ONLINE_PREFIX;
List<UserTokenInfo> onLineUser = (List<UserTokenInfo>) redisUtil.getLikeListAllValues(onlineUserKey);
if(CollectionUtil.isNotEmpty(onLineUser)){
String finalUsername = username;
onLineUser = onLineUser.stream().filter(item->{
JSONObject jsonObject = AuthPubUtil.getLoginByToken(item.getRefreshToken());
String login = jsonObject.getStr(SecurityConstants.USER_NAME_KEY);
long exp = Long.parseLong(jsonObject.getStr(SecurityConstants.JWT_EXP));
long now = Calendar.getInstance().getTimeInMillis()/1000;
return (exp > now) && !login.equals(finalUsername);
}).collect(Collectors.toList());
}
Integer maxNum = data.getMaxNum();
if((CollectionUtil.isNotEmpty(onLineUser)?onLineUser.size():0)>=maxNum){
throw new BusinessException(UserResponseEnum.LOGIN_USER_OVERLIMIT);
}
if (grantType.equalsIgnoreCase(SecurityConstants.REFRESH_TOKEN_KEY)) {
//如果是刷新token需要去黑名单校验
userTokenService.judgeRefreshToken(parameters.get(SecurityConstants.REFRESH_TOKEN_KEY));
}
RequestUtil.saveLoginName(username);
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
//用户的登录名&密码校验成功后,判断当前该用户是否可以正常使用系统
if (!grantType.equalsIgnoreCase(SecurityConstants.GRANT_SMS_CODE)) {
userFeignClient.judgeUserStatus(username);
}
//登录成功后记录token信息并处理踢人效果
userTokenService.recordUserInfo(oAuth2AccessToken, RequestUtil.getRealIp());
if (!grantType.equalsIgnoreCase(SecurityConstants.PASSWORD)) {
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, oAuth2AccessToken, methodDescribe);
} else {
return oAuth2AccessToken;
}
}
@OperateInfo(info = LogEnum.SYSTEM_SERIOUS, operateType = OperateType.LOGOUT)
@ApiOperation("用户登出系统")
@DeleteMapping("/logout")
public HttpResult<Object> logout() {
String methodDescribe = getMethodDescribe("logout");
String userIndex = RequestUtil.getUserIndex();
String username = RequestUtil.getUsername();
LogUtil.njcnDebug(log, "{},用户名为:{}", methodDescribe, username);
String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex;
String onlineUserKey = SecurityConstants.TOKEN_ONLINE_PREFIX + userIndex;
Object onlineTokenInfoOld = redisUtil.getObjectByKey(onlineUserKey);
List<UserTokenInfo> blackUsers = (List<UserTokenInfo>) redisUtil.getObjectByKey(blackUserKey);
UserTokenInfo userTokenInfo;
if (!Objects.isNull(onlineTokenInfoOld)) {
//清除在线token信息
redisUtil.delete(onlineUserKey);
userTokenInfo = (UserTokenInfo) onlineTokenInfoOld;
if (CollectionUtils.isEmpty(blackUsers)) {
blackUsers = new ArrayList<>();
}
blackUsers.add(userTokenInfo);
LocalDateTime refreshTokenExpire = userTokenInfo.getRefreshTokenExpire();
long lifeTime = Math.abs(refreshTokenExpire.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
redisUtil.saveByKeyWithExpire(blackUserKey, blackUsers, lifeTime);
}
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
}
/**
* 文档隐藏该接口
*/
@ApiIgnore
@ApiOperation("RSA公钥获取接口")
@GetMapping("/getPublicKey")
public Map<String, Object> getPublicKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
/**
* 自动登录
*/
@OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.AUTHENTICATE)
@ApiOperation("自动登录")
@PostMapping("/autoLogin")
@ApiImplicitParam(name = "phone", value = "手机号", required = true, paramType = "query")
@ApiIgnore
public HttpResult<Object> autoLogin(@RequestParam String phone) {
String methodDescribe = getMethodDescribe("autoLogin");
String userUrl = "http://127.0.0.1:10214/oauth/token";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(userUrl)
.queryParam("grant_type", "sms_code")
.queryParam("client_id", "njcnapp")
.queryParam("client_secret", "njcnpqs")
.queryParam("phone", phone)
.queryParam("smsCode", "123456789");
URI uri = builder.build().encode().toUri();
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, Objects.requireNonNull(RestTemplateUtil.post(uri, HttpResult.class).getBody()).getData(), methodDescribe);
}
}