From bfd6ec188b9f174c48516600a3d2eace8f2a5a5f Mon Sep 17 00:00:00 2001
From: sxu <602087911@qq.com>
Date: Mon, 19 May 2025 10:29:21 +0800
Subject: [PATCH] OAUTH
---
bonus-auth/pom.xml | 5 +
.../com/bonus/auth/config/OAuth2Config.java | 67 +++++
.../auth/controller/TicketController.java | 275 ++++++++----------
3 files changed, 201 insertions(+), 146 deletions(-)
create mode 100644 bonus-auth/src/main/java/com/bonus/auth/config/OAuth2Config.java
diff --git a/bonus-auth/pom.xml b/bonus-auth/pom.xml
index cc21a7d..2129a99 100644
--- a/bonus-auth/pom.xml
+++ b/bonus-auth/pom.xml
@@ -113,6 +113,11 @@
spring-security-oauth2
2.5.2.RELEASE
+
+ org.springframework.security
+ spring-security-jwt
+ 1.1.1.RELEASE
+
diff --git a/bonus-auth/src/main/java/com/bonus/auth/config/OAuth2Config.java b/bonus-auth/src/main/java/com/bonus/auth/config/OAuth2Config.java
new file mode 100644
index 0000000..35313c1
--- /dev/null
+++ b/bonus-auth/src/main/java/com/bonus/auth/config/OAuth2Config.java
@@ -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());
+ }
+}
\ No newline at end of file
diff --git a/bonus-auth/src/main/java/com/bonus/auth/controller/TicketController.java b/bonus-auth/src/main/java/com/bonus/auth/controller/TicketController.java
index 8ec8b76..daca620 100644
--- a/bonus-auth/src/main/java/com/bonus/auth/controller/TicketController.java
+++ b/bonus-auth/src/main/java/com/bonus/auth/controller/TicketController.java
@@ -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 redisTemplate;
+
+ @Resource
+ private TokenStore tokenStore;
+
+ /**
+ * 获得用户token、userId、当前时间加密的字符串
+ * 跳转第三方菜单时,获取 登录凭证 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 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;
-//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 com.bonus.system.api.domain.SysDept;
-//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 redisTemplate;
-//
-// @Resource
-// private TokenStore tokenStore;
-//
-// @Resource
-// private ISysThirdClientAccreditService thirdClientAccreditService;
-//
-//
-// /**
-// * 获得用户token、userId、当前时间加密的字符串
-// * 跳转第三方菜单时,获取 登录凭证 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;
-// }
+// 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", "");
// }
-// 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, "令牌为空!");
-// }
-// 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 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);
-// }
-//
-//}
+
+ log.info("第三方系统Ticket校验成功:appId:{} ticket:{} Ticket生成时间:{}",appId,ticket,ticketInfoArr[1]);
+ return AjaxResult.success(result);
+ }
+
+}