@@ -25,13 +25,17 @@ 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 com.sgcc.epri.auth.session.HttpSessionManager ;
import io.swagger.annotations.Api ;
import io.swagger.annotations.ApiImplicitParam ;
import io.swagger.annotations.ApiImplicitParams ;
import io.swagger.annotations.ApiOperation ;
import lombok.All ArgsConstructor ;
import lombok.Required ArgsConstructor ;
import lombok.extern.slf4j.Slf4j ;
import org.apache.commons.collections.CollectionUtils ;
import org.springframework.beans.factory.annotation.Value ;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken ;
import org.springframework.security.core.Authentication ;
import org.springframework.security.oauth2.common.OAuth2AccessToken ;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint ;
import org.springframework.web.HttpRequestMethodNotSupportedException ;
@@ -39,6 +43,10 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder ;
import springfox.documentation.annotations.ApiIgnore ;
import javax.servlet.http.Cookie ;
import javax.servlet.http.HttpServletRequest ;
import javax.servlet.http.HttpServletResponse ;
import java.io.IOException ;
import java.net.URI ;
import java.security.KeyPair ;
import java.security.Principal ;
@@ -55,7 +63,7 @@ import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping ( " /oauth " )
@All ArgsConstructor
@Required ArgsConstructor
public class AuthController extends BaseController {
@@ -71,6 +79,11 @@ public class AuthController extends BaseController {
private final UserTokenService userTokenService ;
@Value ( " ${cas.redirect-url:http://10.21.30.11:8088/#/login?flag=1} " )
private String redirectUrl ;
private String UsernamePrefix = " CAS_ " ;
@ApiIgnore
@OperateInfo ( info = LogEnum . SYSTEM_SERIOUS , operateType = OperateType . AUTHENTICATE )
@@ -91,7 +104,6 @@ public class AuthController extends BaseController {
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 ) ;
@@ -104,19 +116,19 @@ public class AuthController extends BaseController {
UserStrategy data = passWordRuleFeugnClient . getUserStrategy ( ) . getData ( ) ;
String onlineUserKey = SecurityConstants . TOKEN_ONLINE_PREFIX ;
List < UserTokenInfo > onLineUser = ( List < UserTokenInfo > ) redisUtil . getLikeListAllValues ( onlineUserKey ) ;
if ( CollectionUtil . isNotEmpty ( onLineUser ) ) {
if ( CollectionUtil . isNotEmpty ( onLineUser ) ) {
String finalUsername = username ;
onLineUser = onLineUser . stream ( ) . filter ( item - > {
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 ) ;
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 ) {
if ( ( CollectionUtil . isNotEmpty ( onLineUser ) ? onLineUser . size ( ) : 0 ) > = maxNum ) {
throw new BusinessException ( UserResponseEnum . LOGIN_USER_OVERLIMIT ) ;
}
@@ -143,7 +155,7 @@ public class AuthController extends BaseController {
@OperateInfo ( info = LogEnum . SYSTEM_SERIOUS , operateType = OperateType . LOGOUT )
@ApiOperation ( " 用户登出系统 " )
@DeleteMapping ( " /logout " )
public HttpResult < Object > logout ( ) {
public HttpResult < Object > logout ( HttpServletRequest request , HttpServletResponse response ) {
String methodDescribe = getMethodDescribe ( " logout " ) ;
String userIndex = RequestUtil . getUserIndex ( ) ;
String username = RequestUtil . getUsername ( ) ;
@@ -165,6 +177,24 @@ public class AuthController extends BaseController {
long lifeTime = Math . abs ( refreshTokenExpire . plusMinutes ( 5L ) . toEpochSecond ( ZoneOffset . of ( " +8 " ) ) - LocalDateTime . now ( ) . toEpochSecond ( ZoneOffset . of ( " +8 " ) ) ) ;
redisUtil . saveByKeyWithExpire ( blackUserKey , blackUsers , lifeTime ) ;
}
// 以下代码是辽宁登出代码,关键:使 Session 失效
request . getSession ( ) . invalidate ( ) ;
// 清除 JSESSIONID
Cookie jsessionidCookie = new Cookie ( " JSESSIONID " , null ) ;
jsessionidCookie . setMaxAge ( 0 ) ;
jsessionidCookie . setPath ( " / " ) ;
response . addCookie ( jsessionidCookie ) ;
// 清除 loginUser Cookie( 关键! )
Cookie loginUserCookie = new Cookie ( " loginUser " , null ) ;
loginUserCookie . setMaxAge ( 0 ) ;
loginUserCookie . setPath ( " / " ) ;
response . addCookie ( loginUserCookie ) ;
log . info ( " 登出成功。。。。。。。。。。。。。。。。 " ) ;
return HttpResultUtil . assembleCommonResponseResult ( CommonResponseEnum . SUCCESS , null , methodDescribe ) ;
}
@@ -186,20 +216,152 @@ public class AuthController extends BaseController {
*/
@OperateInfo ( info = LogEnum . SYSTEM_COMMON , operateType = OperateType . AUTHENTICATE )
@ApiOperation ( " 自动登录 " )
@Pos tMapping ( " /autoLogin " )
@Ge tMapping ( " /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 ( " grant_type " , SecurityConstants . GRANT_AUTHORIZATION_CODE )
. queryParam ( " client_id " , " njcn " )
. queryParam ( " client_secret " , " njcnpqs " )
. queryParam ( " phon e" , phone )
. queryParam ( " sms Code" , " 123456789 " ) ;
. queryParam ( " usernam e" , " %2FPY4%2FD07ExoKDUg6yCi2cA%3D%3D " )
. queryParam ( " image Code" , " verifyCode " )
. queryParam ( " verifyCode " , " 0 " ) ;
URI uri = builder . build ( ) . encode ( ) . toUri ( ) ;
return HttpResultUtil . assembleCommonResponseResult ( CommonResponseEnum . SUCCESS , Objects . requireNonNull ( RestTemplateUtil . post ( uri , HttpResult . class ) . getBody ( ) ) . getData ( ) , methodDescribe ) ;
}
/**
* 【电科院CAS调控云单点登录适配】
* 这个只用来匹配
*/
@ApiIgnore
@GetMapping ( " /lnLogin " )
@ApiOperation ( " 获取ln系统用户token " )
public HttpResult < Object > lnLogin ( @RequestParam String clientId , @RequestParam String clientSecret , HttpServletRequest request , HttpServletResponse response ) throws HttpRequestMethodNotSupportedException {
log . info ( " 进入lnLogin++++++++++++++++++ " ) ;
String methodDescribe = getMethodDescribe ( " lnLogin " ) ;
// 读取CAS信息
String userName = String . valueOf ( HttpSessionManager . getAttribute ( request , HttpSessionManager . AUTH_USER_KEY ) ) ;
String userId = String . valueOf ( HttpSessionManager . getAttribute ( request , HttpSessionManager . USER_ID_KEY ) ) ;
String owner = String . valueOf ( HttpSessionManager . getAttribute ( request , HttpSessionManager . USER_OWNER ) ) ;
String name = String . valueOf ( HttpSessionManager . getAttribute ( request , HttpSessionManager . USER_NAME_CHN ) ) ;
String employeeId = String . valueOf ( HttpSessionManager . getAttribute ( request , HttpSessionManager . USER_EMPLOYEE_ID ) ) ;
log . info ( " userName:{} " , userName ) ;
log . info ( " userId:{} " , userId ) ;
log . info ( " owner:{} " , owner ) ;
log . info ( " name:{} " , name ) ;
log . info ( " employeeId:{} " , employeeId ) ;
if ( " null " . equals ( userName ) ) {
throw new BusinessException ( UserResponseEnum . LN_AUTH_ERROR ) ;
}
// 2. 【关键】用户名前面加上"CAS_"前缀, 让UserDetailsService识别
String casUsername = userName ;
// 2. 直接构造 OAuth2 必要参数(跳过所有密码/加密校验)
Map < String , String > parameters = new HashMap < > ( ) ;
parameters . put ( " grant_type " , " password " ) ; // 固定密码模式
parameters . put ( " client_id " , clientId ) ; // 你的客户端ID
parameters . put ( " client_secret " , clientSecret ) ; // 你的客户端秘钥
parameters . put ( " username " , userName ) ; // 统一认证传过来的用户名
parameters . put ( " password " , " @#001njcnpqs " ) ;
// 3. 直接调用 OAuth2 生成 Token( 跳过所有登录校验)
Authentication authentication = new UsernamePasswordAuthenticationToken (
clientId , clientSecret , Collections . emptyList ( )
) ;
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint . postAccessToken ( authentication , parameters ) . getBody ( ) ;
// 获取过期时间(秒数)
int expiresIn = oAuth2AccessToken . getExpiresIn ( ) ;
log . info ( " token过期时间: {} 秒 " , expiresIn ) ;
log . info ( " token过期时间: {} 分钟 " , expiresIn / 60 ) ;
log . info ( " token过期时间: {} 小时 " , expiresIn / 3600 ) ;
log . info ( " ====== 免密登录成功, 返回token给前端 ====== " ) ;
return HttpResultUtil . assembleCommonResponseResult ( CommonResponseEnum . SUCCESS , oAuth2AccessToken , methodDescribe ) ;
}
/**
* 重点:
* 这个接口 不加 白名单
* 访问它 → 自动跳CAS → 登录成功 → 重定向到登录页
*/
@GetMapping ( " /lnCheck " )
@ApiOperation ( " 检查CAS是否登录 " )
public void lnToken ( HttpServletRequest request , HttpServletResponse response ) throws IOException {
log . info ( " 进入lnCheck。。。。 " ) ;
response . sendRedirect ( redirectUrl ) ;
}
/**
*/
@GetMapping ( " /lnRefreshToken " )
@ApiOperation ( " 刷新token " )
public HttpResult < Object > lnRefreshToken (
@RequestParam String refreshToken ,
@RequestParam String clientId ,
@RequestParam String clientSecret ,
HttpServletRequest request ,
HttpServletResponse response ) throws HttpRequestMethodNotSupportedException {
log . info ( " 进入lnRefreshToken, 开始刷新token " ) ;
String methodDescribe = getMethodDescribe ( " lnRefreshToken " ) ;
// ========== 【前置: 优先校验CAS会话是否过期】 ==========
String userName = String . valueOf ( HttpSessionManager . getAttribute ( request , HttpSessionManager . AUTH_USER_KEY ) ) ;
if ( " null " . equals ( userName ) ) {
log . error ( " CAS会话已过期, 跳转登录页 " ) ;
throw new BusinessException ( UserResponseEnum . LN_AUTH_ERROR ) ;
}
// 1. 先尝试用refresh_token正常刷新
Map < String , String > parameters = new HashMap < > ( ) ;
parameters . put ( " grant_type " , " refresh_token " ) ;
parameters . put ( " refresh_token " , refreshToken ) ;
parameters . put ( " client_id " , clientId ) ;
parameters . put ( " client_secret " , clientSecret ) ;
Authentication authentication = new UsernamePasswordAuthenticationToken (
clientId , clientSecret , Collections . emptyList ( )
) ;
try {
OAuth2AccessToken newAccessToken = tokenEndpoint . postAccessToken ( authentication , parameters ) . getBody ( ) ;
log . info ( " refresh_token刷新成功 " ) ;
return HttpResultUtil . assembleCommonResponseResult ( CommonResponseEnum . SUCCESS , newAccessToken , methodDescribe ) ;
} catch ( Exception e ) {
log . warn ( " refresh_token刷新失败, 尝试回退到CAS会话重新签发token " , e ) ;
}
// 3. CAS会话有效, 重新签发token( 等同于重新登录)
log . info ( " CAS会话有效, 为用户[{}]重新签发token " , userName ) ;
String casUsername = userName ;
Map < String , String > reLoginParams = new HashMap < > ( ) ;
reLoginParams . put ( " grant_type " , " password " ) ;
reLoginParams . put ( " client_id " , clientId ) ;
reLoginParams . put ( " client_secret " , clientSecret ) ;
reLoginParams . put ( " username " , userName ) ;
reLoginParams . put ( " password " , " @#001njcnpqs " ) ;
Authentication reAuth = new UsernamePasswordAuthenticationToken (
clientId , clientSecret , Collections . emptyList ( )
) ;
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint . postAccessToken ( reAuth , reLoginParams ) . getBody ( ) ;
log . info ( " CAS回退重签token成功, userName:{} " , userName ) ;
return HttpResultUtil . assembleCommonResponseResult ( CommonResponseEnum . SUCCESS , oAuth2AccessToken , methodDescribe ) ;
}
}