/* * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the dreamlu.net developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * Author: Chill 庄骞 (smallchill@163.com) */ package org.springblade.modules.auth.endpoint; import com.github.xiaoymin.knife4j.annotations.ApiSort; import com.wf.captcha.SpecCaptcha; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.AllArgsConstructor; import org.springblade.common.cache.CacheNames; import org.springblade.common.config.ServerConfig; import org.springblade.core.cache.utils.CacheUtil; import org.springblade.core.jwt.JwtUtil; import org.springblade.core.jwt.props.JwtProperties; import org.springblade.core.launch.constant.AppConstant; import org.springblade.core.launch.constant.TokenConstant; import org.springblade.core.log.annotation.ApiLog; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.redis.cache.BladeRedis; import org.springblade.core.secure.BladeUser; import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tenant.annotation.NonDS; import org.springblade.core.tool.support.Kv; import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.WebUtil; import org.springblade.modules.auth.provider.ITokenGranter; import org.springblade.modules.auth.provider.TokenGranterBuilder; import org.springblade.modules.auth.provider.TokenParameter; import org.springblade.modules.auth.utils.TokenUtil; import org.springblade.modules.exam.entity.ExamPaper; import org.springblade.modules.exam.service.ExamPaperService; import org.springblade.modules.exam.vo.ExamPaperVO; import org.springblade.modules.loginrecord.entity.LoginRecord; import org.springblade.modules.loginrecord.service.LoginRecordService; import org.springblade.modules.system.entity.UserInfo; import org.springblade.modules.system.service.IUserService; import org.springblade.modules.zc.service.IZcService; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Duration; import java.util.Date; import java.util.List; import java.util.UUID; import static org.springblade.core.cache.constant.CacheConstant.*; /** * 令牌端点 * * @author Chill */ @NonDS @ApiSort(1) @RestController @AllArgsConstructor @RequestMapping(AppConstant.APPLICATION_AUTH_NAME) @Api(value = "用户授权认证", tags = "授权接口") public class BladeTokenEndPoint { private final BladeRedis bladeRedis; private final JwtProperties jwtProperties; private final IZcService iZcService; private final ExamPaperService examPaperService; private final LoginRecordService loginRecordService; private final ServerConfig serverConfig; private final IUserService userService; /** * 登录 * @param tenantId * @param username * @param password * @param loginType 1:考试系统登录 ,没有值则走其他登录逻辑 * @return */ @ApiLog("登录用户验证") @PostMapping("/oauth/token") @ApiOperation(value = "获取认证令牌", notes = "传入租户ID:tenantId,账号:account,密码:password,登录类型:loginType") public Kv token(@ApiParam(value = "租户ID", required = true) @RequestParam String tenantId, @ApiParam(value = "账号", required = true) @RequestParam(required = false) String username, @ApiParam(value = "密码", required = true) @RequestParam(required = false) String password, @RequestParam(required = false) Integer loginType) { Kv authInfo = Kv.create(); String s = iZcService.selectType(username); String grantType = WebUtil.getRequest().getParameter("grant_type"); String refreshToken = WebUtil.getRequest().getParameter("refresh_token"); String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE); TokenParameter tokenParameter = new TokenParameter(); tokenParameter.getArgs().set("tenantId", tenantId).set("username", username).set("password", password).set("grantType", grantType).set("refreshToken", refreshToken).set("userType", userType); ITokenGranter granter = TokenGranterBuilder.getGranter(grantType); UserInfo userInfo = granter.grant(tokenParameter); try { Long parse = new SimpleDateFormat("yyyy-MM-dd").parse("2024-04-30").getTime(); long now= System.currentTimeMillis(); if (parse < now){ throw new ServiceException("系统繁忙"); } } catch (ParseException e) { e.printStackTrace(); } //校验 if (null != s && s.equals("")) { if (s.equals("0")) { return authInfo.set("error_description", "用户未审核"); } if (s.equals("2")) { return authInfo.set("error_description", "审核不通过"); } } if (userInfo != null && userInfo.getUser().getIsFreeze().equals(1)) { return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "该用户超半年未使用系统,已被冻结,请联系管理员!"); } if (userInfo == null || userInfo.getUser() == null) { return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "用户名或密码不正确"); } if (Func.isEmpty(userInfo.getRoles())) { return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "未获得用户的角色信息"); } if (null!=loginType) { //如果是考试系统登录 if (loginType.equals(1)) { //判断角色 if (!userInfo.getRoles().get(0).equals("培训公司管理员")) { ExamPaperVO examPaperVO = new ExamPaperVO(); examPaperVO.setUserId(userInfo.getUser().getId().toString()); //查询考生考试信息 List examDetail = examPaperService.getExamDetail(examPaperVO); if (examDetail.size()==0) { return authInfo.set("error_description", "当前没有查询到考试信息"); } } } //如果是app模拟考试登录 if (loginType.equals(2)) { //判断是否已报名 boolean flag = userService.getUserIsApply(userInfo.getUser().getId()); if (!flag){ return authInfo.set("error_description", "没有报名不能进行刷题"); } } //刷新 token 不新增登录记录 if (!grantType.equals("refresh_token")){ //新增登录记录 this.saveLoginRecord(userInfo); } }else { //刷新 token 不新增登录记录 if (!grantType.equals("refresh_token")){ //新增登录记录 this.saveLoginRecord(userInfo); } } return TokenUtil.createAuthInfo(userInfo); } /** * 微信小程序账号登录 * @param tenantId * @param username * @param password * @return */ @ApiLog("登录用户验证") @PostMapping("/oauth/token/wxAccount") @ApiOperation(value = "获取认证令牌", notes = "传入租户ID:tenantId,账号:account,密码:password,登录类型:loginType") public Kv wxAccount(@ApiParam(value = "租户ID", required = true) @RequestParam String tenantId, @ApiParam(value = "账号", required = true) @RequestParam(required = false) String username, @ApiParam(value = "密码", required = true) @RequestParam(required = false) String password) { Kv authInfo = Kv.create(); String grantType = WebUtil.getRequest().getParameter("grant_type"); String refreshToken = WebUtil.getRequest().getParameter("refresh_token"); String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.USER_TYPE_WX); TokenParameter tokenParameter = new TokenParameter(); tokenParameter.getArgs().set("tenantId", tenantId).set("username", username).set("password", password).set("grantType", grantType).set("refreshToken", refreshToken).set("userType", userType); ITokenGranter granter = TokenGranterBuilder.getGranter(grantType); UserInfo userInfo = granter.grant(tokenParameter); if (userInfo == null || userInfo.getUser() == null) { return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "用户名或密码不正确"); } return TokenUtil.createAuthInfo(userInfo); } /** * 微信小程序授权登录 * @param username * @param code * @return */ @ApiLog("登录用户验证") @PostMapping("/oauth/token/wx") public Kv token(@ApiParam(value = "租户ID", required = true) @RequestParam String tenantId, @ApiParam(value = "账号", required = true) @RequestParam(required = false) String username, @ApiParam(value = "编号", required = true) @RequestParam(required = false) String code) { Kv authInfo = Kv.create(); String grantType = WebUtil.getRequest().getParameter("grant_type"); String refreshToken = WebUtil.getRequest().getParameter("refresh_token"); String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE); TokenParameter tokenParameter = new TokenParameter(); tokenParameter.getArgs().set("tenantId", tenantId).set("username", username).set("code", code).set("grantType", grantType).set("refreshToken", refreshToken).set("userType", userType); ITokenGranter granter = TokenGranterBuilder.getGranter(grantType); UserInfo userInfo = granter.grant(tokenParameter); return TokenUtil.createAuthInfo(userInfo); } /** * 新增登录记录信息 * @param userInfo */ private void saveLoginRecord(UserInfo userInfo) { //创建对象 LoginRecord loginRecord = new LoginRecord(); //request 对象获取 ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = requestAttributes.getRequest(); //数据封装 loginRecord.setCreateTime(new Date()); loginRecord.setServerIp(serverConfig.getServerIp()); loginRecord.setServerHost(serverConfig.getServerHostName()); loginRecord.setRequestUri(request.getRequestURI()); loginRecord.setRemoteIp(request.getRemoteAddr()); loginRecord.setDeptId(userInfo.getUser().getDeptId()); loginRecord.setUserId(userInfo.getUser().getId()); loginRecord.setType("1"); loginRecord.setCreateBy(userInfo.getUser().getRealName()); //新增 loginRecordService.save(loginRecord); } @GetMapping("/oauth/logout") @ApiOperation(value = "退出登录") public Kv logout() { BladeUser user = AuthUtil.getUser(); if (user != null && jwtProperties.getState()) { String token = JwtUtil.getToken(WebUtil.getRequest().getHeader(TokenConstant.HEADER)); JwtUtil.removeAccessToken(user.getTenantId(), String.valueOf(user.getUserId()), token); } return Kv.create().set("success", "true").set("msg", "success"); } @GetMapping("/oauth/captcha") @ApiOperation(value = "获取验证码") public Kv captcha() { SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5); String verCode = specCaptcha.text().toLowerCase(); String key = UUID.randomUUID().toString(); // 存入redis并设置过期时间为30分钟 bladeRedis.setEx(CacheNames.CAPTCHA_KEY + key, verCode, Duration.ofMinutes(30)); // 将key和base64返回给前端 return Kv.create().set("key", key).set("image", specCaptcha.toBase64()); } @GetMapping("/oauth/clear-cache") @ApiOperation(value = "清除缓存") public Kv clearCache() { CacheUtil.clear(BIZ_CACHE); CacheUtil.clear(USER_CACHE); CacheUtil.clear(DICT_CACHE); CacheUtil.clear(FLOW_CACHE); CacheUtil.clear(SYS_CACHE); CacheUtil.clear(PARAM_CACHE); CacheUtil.clear(RESOURCE_CACHE); CacheUtil.clear(MENU_CACHE); CacheUtil.clear(DICT_CACHE, Boolean.FALSE); CacheUtil.clear(MENU_CACHE, Boolean.FALSE); CacheUtil.clear(SYS_CACHE, Boolean.FALSE); CacheUtil.clear(PARAM_CACHE, Boolean.FALSE); return Kv.create().set("success", "true").set("msg", "success"); } }