This commit is contained in:
sxu 2025-05-19 10:29:21 +08:00
parent a93959f1f2
commit bfd6ec188b
3 changed files with 201 additions and 146 deletions

View File

@ -113,6 +113,11 @@
<artifactId>spring-security-oauth2</artifactId> <artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version> <version>2.5.2.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
</dependencies> </dependencies>

View File

@ -0,0 +1,67 @@
package com.bonus.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
// Configure the token store and JWT converter
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("your-256-bit-secret"); // Use a secure key in production
return converter;
}
// Configure security constraints on the token endpoint
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()") // Public key for token verification
.checkTokenAccess("isAuthenticated()") // Token validation endpoint
.allowFormAuthenticationForClients();
}
// Configure client details service
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id") // Your client ID
.secret(passwordEncoder.encode("client-secret")) // Your client secret
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600) // 1 hour
.refreshTokenValiditySeconds(86400); // 24 hours
}
// Configure the endpoints
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
}

View File

@ -1,149 +1,132 @@
//package com.bonus.auth.controller; package com.bonus.auth.controller;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.RemoteUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@RestController
@RequestMapping("/ticket")
public class TicketController {
@Resource
private RemoteUserService remoteUserService;
@Resource
public RedisTemplate<String, String> redisTemplate;
@Resource
private TokenStore tokenStore;
/**
* 获得用户tokenuserId当前时间加密的字符串
* 跳转第三方菜单时获取 登录凭证 Ticket
* 将Ticket记录在redis中设置时效 60s,记录用户id用户的token和当前时间
*/
@GetMapping("getUserTicket")
public String getUserTicket() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof OAuth2Authentication) {
Object details = authentication.getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails detail = (OAuth2AuthenticationDetails) details;
String tokenValue = detail.getTokenValue();
String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
Long userId = SecurityUtils.getUserId();
String ticket = tokenValue + "," + dateStr + "," + userId;
String encryptedString = Sm4Utils.encrypt(ticket);
if (encryptedString != null) {
String uuid = UuidUtils.generateUuid();
redisTemplate.opsForValue().set(uuid, encryptedString, 60, TimeUnit.SECONDS);
return uuid;
}
}
}
throw new RuntimeException("未知错误");
}
/**
* 登录凭证 Ticket校验
* 第三方系统拿到Ticket后需要校验该Ticket有效性校验通过返回用户信息
* @param ticket登录凭证
* @param appId第三方系统注册颁发的APPID唯一标识用来控制第三方系统的接入
* @return
*/
@GetMapping("validate")
public AjaxResult getUserInfo(String ticket, String appId) {
if (appId==null || "".equals(appId)) {
log.error("第三方系统Ticket校验失败: ticket{} 结果 :{} ",ticket,"APPID为空");
return new AjaxResult(10000, "APPID为空!");
}
if (ticket==null || "".equals(ticket)) {
log.error("第三方系统Ticket校验失败:appId{} 结果 :{} ",appId,"令牌为空");
return new AjaxResult(10001, "令牌为空!");
}
String encryptedString = redisTemplate.opsForValue().get(ticket);
if (StringUtils.isBlank(encryptedString)) {
log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"令牌已失效");
return new AjaxResult(10003, "令牌已失效!");
}
String realTicket = Sm4Utils.decrypt(encryptedString);
if (StringUtils.isBlank(realTicket)) {
log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"令牌解析错误");
return new AjaxResult(10004, "令牌解析错误!");
}
String[] ticketInfoArr = realTicket.split(",");
String tokenValue = ticketInfoArr[0];
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StringUtils.isEmpty(accessToken.getValue())) {
log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"当前用户已离线,请重新登录");
return new AjaxResult(10005, "当前用户已离线,请重新登录!");
}
String userId = ticketInfoArr[2];
AjaxResult result = remoteUserService.getInfo(Long.parseLong(userId), SecurityConstants.INNER);
// Map<String, Object> resMap = new HashMap<>();
// resMap.put("userName", sysUser.getUserName());
// resMap.put("name", sysUser.getNickName());
// resMap.put("deptId", sysUser.getDeptId());
// resMap.put("deptName", sysUser.getDept() == null ? null : sysUser.getDept().getDeptName().replaceAll("YJ", ""));
// //
//import com.alibaba.nacos.common.utils.UuidUtils; // SysDept dept = sysUser.getDept();
//import com.bonus.common.core.constant.SecurityConstants; // 特定的业务需求需要记录当前用户是否为运检站,并且返回 xx站
//import com.bonus.common.core.utils.encryption.Sm4Utils; // if (dept != null) {
//import com.bonus.common.core.web.domain.AjaxResult; // if ("4".equals(dept.getDeptType()) && dept.getDeptName().contains("")) {
//import com.bonus.common.security.utils.SecurityUtils; // resMap.put("businessDeptName", dept.getDeptName().replaceAll("YJ", ""));
//import com.bonus.system.api.RemoteUserService; // } else {
//import com.bonus.system.api.domain.SysDept; // resMap.put("businessDeptName", "");
//import com.bonus.system.api.domain.SysUser;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.lang3.StringUtils;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.security.core.Authentication;
//import org.springframework.security.core.context.SecurityContextHolder;
//import org.springframework.security.oauth2.common.OAuth2AccessToken;
//import org.springframework.security.oauth2.provider.OAuth2Authentication;
//import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
//import org.springframework.security.oauth2.provider.token.TokenStore;
//import org.springframework.web.bind.annotation.GetMapping;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RestController;
//import javax.annotation.Resource;
//import java.text.SimpleDateFormat;
//import java.util.Date;
//import java.util.HashMap;
//import java.util.Map;
//import java.util.concurrent.TimeUnit;
//
///**
// * 第三方系统接入
// * @author semdo
// */
//@Slf4j
//@RestController
//@RequestMapping("/ticket")
//public class TicketController {
// @Resource
// private RemoteUserService remoteUserService;
//
// @Resource
// public RedisTemplate<String, String> redisTemplate;
//
// @Resource
// private TokenStore tokenStore;
//
// @Resource
// private ISysThirdClientAccreditService thirdClientAccreditService;
//
//
// /**
// * 获得用户tokenuserId当前时间加密的字符串
// * 跳转第三方菜单时获取 登录凭证 Ticket
// * 将Ticket记录在redis中设置时效 60s,记录用户id用户的token和当前时间
// */
// @GetMapping("getUserTicket")
// public String getUserTicket() {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// if (authentication instanceof OAuth2Authentication) {
// Object details = authentication.getDetails();
// if (details instanceof OAuth2AuthenticationDetails) {
// OAuth2AuthenticationDetails detail = (OAuth2AuthenticationDetails) details;
// String tokenValue = detail.getTokenValue();
// String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
// Long userId = SecurityUtils.getUserId();
// String ticket = tokenValue + "," + dateStr + "," + userId;
// String encryptedString = Sm4Utils.encrypt(ticket);
// if (encryptedString != null) {
// String uuid = UuidUtils.generateUuid();
// redisTemplate.opsForValue().set(uuid, encryptedString, 60, TimeUnit.SECONDS);
// return uuid;
// }
// } // }
// } else {
// resMap.put("businessDeptName", "");
// } // }
// throw new RuntimeException("未知错误");
// } log.info("第三方系统Ticket校验成功:appId{} ticket{} Ticket生成时间{}",appId,ticket,ticketInfoArr[1]);
// return AjaxResult.success(result);
// /** }
// * 登录凭证 Ticket校验
// * 第三方系统拿到Ticket后需要校验该Ticket有效性校验通过返回用户信息 }
// * @param ticket登录凭证
// * @param appId第三方系统注册颁发的APPID唯一标识用来控制第三方系统的接入
// * @return
// */
// @GetMapping("validate")
// public AjaxResult getUserInfo(String ticket, String appId) {
// if (appId==null || "".equals(appId)) {
// log.error("第三方系统Ticket校验失败: ticket{} 结果 :{} ",ticket,"APPID为空");
// return new AjaxResult(10000, "APPID为空!");
// }
// if (ticket==null || "".equals(ticket)) {
// log.error("第三方系统Ticket校验失败:appId{} 结果 :{} ",appId,"令牌为空");
// return new AjaxResult(10001, "令牌为空!");
// }
// boolean appStatus = thirdClientAccreditService.getAppStatusByAppId(appId);
//
// if (!appStatus) {
// log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"应用不可用");
// return new AjaxResult(10002, "应用不可用!");
// }
//
//
// String encryptedString = redisTemplate.opsForValue().get(ticket);
// if (StringUtils.isBlank(encryptedString)) {
// log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"令牌已失效");
// return new AjaxResult(10003, "令牌已失效!");
// }
//
//
// String realTicket = Sm4Utils.decrypt(encryptedString);
// if (StringUtils.isBlank(realTicket)) {
// log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"令牌解析错误");
// return new AjaxResult(10004, "令牌解析错误!");
// }
// String[] ticketInfoArr = realTicket.split(",");
//
// String tokenValue = ticketInfoArr[0];
// OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
// if (accessToken == null || StringUtils.isEmpty(accessToken.getValue())) {
// log.error("第三方系统Ticket校验失败:appId{} ticket{} 结果 :{} ",appId,ticket,"当前用户已离线,请重新登录");
// return new AjaxResult(10005, "当前用户已离线,请重新登录!");
// }
// String userId = ticketInfoArr[2];
// AjaxResult result = remoteUserService.getInfo(Long.parseLong(userId), SecurityConstants.INNER);
//
//
//// Map<String, Object> resMap = new HashMap<>();
//// resMap.put("userName", sysUser.getUserName());
//// resMap.put("name", sysUser.getNickName());
//// resMap.put("deptId", sysUser.getDeptId());
//// resMap.put("deptName", sysUser.getDept() == null ? null : sysUser.getDept().getDeptName().replaceAll("YJ", ""));
////
//// SysDept dept = sysUser.getDept();
// // 特定的业务需求需要记录当前用户是否为运检站,并且返回 xx站
//// if (dept != null) {
//// if ("4".equals(dept.getDeptType()) && dept.getDeptName().contains("")) {
//// resMap.put("businessDeptName", dept.getDeptName().replaceAll("YJ", ""));
//// } else {
//// resMap.put("businessDeptName", "");
//// }
//// } else {
//// resMap.put("businessDeptName", "");
//// }
//
// log.info("第三方系统Ticket校验成功:appId{} ticket{} Ticket生成时间{}",appId,ticket,ticketInfoArr[1]);
// return AjaxResult.success(result);
// }
//
//}