提交 cd00a039 编写于 作者: MaxKey单点登录官方's avatar MaxKey单点登录官方

OnlineTicket

上级 06b27d35
...@@ -149,6 +149,9 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider ...@@ -149,6 +149,9 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
String onlineTickitId = WebConstants.ONLINE_TICKET_PREFIX + "-" + java.util.UUID.randomUUID().toString().toLowerCase(); String onlineTickitId = WebConstants.ONLINE_TICKET_PREFIX + "-" + java.util.UUID.randomUUID().toString().toLowerCase();
_logger.debug("set online Tickit Cookie " + onlineTickitId + " on domain "+ this.applicationConfig.getBaseDomainName()); _logger.debug("set online Tickit Cookie " + onlineTickitId + " on domain "+ this.applicationConfig.getBaseDomainName());
OnlineTicket onlineTicket = new OnlineTicket(onlineTickitId);
WebContext.setCookie(WebContext.getResponse(), WebContext.setCookie(WebContext.getResponse(),
this.applicationConfig.getBaseDomainName(), this.applicationConfig.getBaseDomainName(),
WebConstants.ONLINE_TICKET_NAME, WebConstants.ONLINE_TICKET_NAME,
...@@ -157,7 +160,7 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider ...@@ -157,7 +160,7 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
SigninPrincipal signinPrincipal = new SigninPrincipal(userInfo); SigninPrincipal signinPrincipal = new SigninPrincipal(userInfo);
//set OnlineTicket //set OnlineTicket
signinPrincipal.setOnlineTicket(onlineTickitId); signinPrincipal.setOnlineTicket(onlineTicket);
ArrayList<GrantedAuthority> grantedAuthoritys = authenticationRealm.grantAuthority(userInfo); ArrayList<GrantedAuthority> grantedAuthoritys = authenticationRealm.grantAuthority(userInfo);
//set default roles //set default roles
grantedAuthoritys.add(new SimpleGrantedAuthority("ROLE_USER")); grantedAuthoritys.add(new SimpleGrantedAuthority("ROLE_USER"));
...@@ -182,8 +185,10 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider ...@@ -182,8 +185,10 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
authenticationToken.setDetails( authenticationToken.setDetails(
new WebAuthenticationDetails(WebContext.getRequest())); new WebAuthenticationDetails(WebContext.getRequest()));
OnlineTicket onlineTicket = new OnlineTicket(onlineTickitId,authenticationToken); onlineTicket.setAuthentication(authenticationToken);
this.onlineTicketServices.store(onlineTickitId, onlineTicket); this.onlineTicketServices.store(onlineTickitId, onlineTicket);
/* /*
* put userInfo to current session context * put userInfo to current session context
*/ */
......
...@@ -20,6 +20,7 @@ package org.maxkey.authn; ...@@ -20,6 +20,7 @@ package org.maxkey.authn;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.maxkey.authn.online.OnlineTicket;
import org.maxkey.domain.UserInfo; import org.maxkey.domain.UserInfo;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
...@@ -31,7 +32,7 @@ public class SigninPrincipal implements UserDetails { ...@@ -31,7 +32,7 @@ public class SigninPrincipal implements UserDetails {
UserDetails userDetails; UserDetails userDetails;
String onlineTicket; OnlineTicket onlineTicket;
ArrayList<GrantedAuthority> grantedAuthority; ArrayList<GrantedAuthority> grantedAuthority;
boolean authenticated; boolean authenticated;
boolean roleAdministrators; boolean roleAdministrators;
...@@ -95,11 +96,11 @@ public class SigninPrincipal implements UserDetails { ...@@ -95,11 +96,11 @@ public class SigninPrincipal implements UserDetails {
this.grantedAuthority = grantedAuthority; this.grantedAuthority = grantedAuthority;
} }
public String getOnlineTicket() { public OnlineTicket getOnlineTicket() {
return onlineTicket; return onlineTicket;
} }
public void setOnlineTicket(String onlineTicket) { public void setOnlineTicket(OnlineTicket onlineTicket) {
this.onlineTicket = onlineTicket; this.onlineTicket = onlineTicket;
} }
......
...@@ -18,15 +18,19 @@ ...@@ -18,15 +18,19 @@
package org.maxkey.authn.online; package org.maxkey.authn.online;
import java.time.Duration; import java.time.Duration;
import java.time.LocalTime;
import org.ehcache.UserManagedCache; import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder; import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder; import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InMemoryOnlineTicketServices implements OnlineTicketServices{ public class InMemoryOnlineTicketServices implements OnlineTicketServices{
private static final Logger _logger = LoggerFactory.getLogger(InMemoryOnlineTicketServices.class);
protected final static UserManagedCache<String, OnlineTicket> onlineTicketStore =
protected static UserManagedCache<String, OnlineTicket> onlineTicketStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OnlineTicket.class) UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OnlineTicket.class)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(30))) .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(30)))
.build(true); .build(true);
...@@ -56,8 +60,37 @@ public class InMemoryOnlineTicketServices implements OnlineTicketServices{ ...@@ -56,8 +60,37 @@ public class InMemoryOnlineTicketServices implements OnlineTicketServices{
@Override @Override
public void setValiditySeconds(int validitySeconds) { public void setValiditySeconds(int validitySeconds) {
// TODO Auto-generated method stub onlineTicketStore =
UserManagedCacheBuilder.
newUserManagedCacheBuilder(String.class, OnlineTicket.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofMinutes(validitySeconds/60))
)
.build(true);
}
@Override
public void refresh(String ticketId,LocalTime refreshTime) {
OnlineTicket onlineTicket = get(ticketId);
onlineTicket.setTicketTime(refreshTime);
store(ticketId , onlineTicket);
}
@Override
public void refresh(String ticketId) {
OnlineTicket onlineTicket = get(ticketId);
LocalTime currentTime = LocalTime.now();
Duration duration = Duration.between(currentTime, onlineTicket.getTicketTime());
_logger.trace("OnlineTicket duration " + duration.getSeconds());
if(duration.getSeconds() > OnlineTicket.MAX_EXPIRY_DURATION) {
onlineTicket.setTicketTime(currentTime);
refresh(ticketId,currentTime);
}
} }
} }
package org.maxkey.authn.online; package org.maxkey.authn.online;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalTime;
import java.util.HashMap; import java.util.HashMap;
import org.maxkey.domain.apps.Apps; import org.maxkey.domain.apps.Apps;
...@@ -11,10 +12,15 @@ public class OnlineTicket implements Serializable{ ...@@ -11,10 +12,15 @@ public class OnlineTicket implements Serializable{
/** /**
* *
*/ */
private static final long serialVersionUID = 9008067569150338296L;
public static final int MAX_EXPIRY_DURATION = 60 * 10; //default 10 minutes.
private static final long serialVersionUID = 9008067569150338296L;
public String ticketId; public String ticketId;
public LocalTime ticketTime;
public Authentication authentication; public Authentication authentication;
private HashMap<String , Apps> authorizedApps = new HashMap<String , Apps>(); private HashMap<String , Apps> authorizedApps = new HashMap<String , Apps>();
...@@ -23,12 +29,14 @@ public class OnlineTicket implements Serializable{ ...@@ -23,12 +29,14 @@ public class OnlineTicket implements Serializable{
public OnlineTicket(String ticketId) { public OnlineTicket(String ticketId) {
super(); super();
this.ticketId = ticketId; this.ticketId = ticketId;
this.ticketTime = LocalTime.now();
} }
public OnlineTicket(String ticketId,Authentication authentication) { public OnlineTicket(String ticketId,Authentication authentication) {
super(); super();
this.ticketId = ticketId; this.ticketId = ticketId;
this.authentication = authentication; this.authentication = authentication;
this.ticketTime = LocalTime.now();
} }
...@@ -44,6 +52,14 @@ public class OnlineTicket implements Serializable{ ...@@ -44,6 +52,14 @@ public class OnlineTicket implements Serializable{
} }
public LocalTime getTicketTime() {
return ticketTime;
}
public void setTicketTime(LocalTime ticketTime) {
this.ticketTime = ticketTime;
}
public Authentication getAuthentication() { public Authentication getAuthentication() {
return authentication; return authentication;
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.maxkey.authn.online; package org.maxkey.authn.online;
import java.time.LocalTime;
public interface OnlineTicketServices { public interface OnlineTicketServices {
...@@ -25,6 +26,10 @@ public interface OnlineTicketServices { ...@@ -25,6 +26,10 @@ public interface OnlineTicketServices {
public OnlineTicket remove(String ticket); public OnlineTicket remove(String ticket);
public OnlineTicket get(String ticketId); public OnlineTicket get(String ticketId);
public void refresh(String ticketId ,LocalTime refreshTime);
public void refresh(String ticketId);
public void setValiditySeconds(int validitySeconds); public void setValiditySeconds(int validitySeconds);
} }
...@@ -17,12 +17,17 @@ ...@@ -17,12 +17,17 @@
package org.maxkey.authn.online; package org.maxkey.authn.online;
import java.time.Duration;
import java.time.LocalTime;
import org.maxkey.persistence.redis.RedisConnection; import org.maxkey.persistence.redis.RedisConnection;
import org.maxkey.persistence.redis.RedisConnectionFactory; import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RedisOnlineTicketServices implements OnlineTicketServices { public class RedisOnlineTicketServices implements OnlineTicketServices {
private static final Logger _logger = LoggerFactory.getLogger(RedisOnlineTicketServices.class);
protected int serviceTicketValiditySeconds = 60 * 30; //default 30 minutes. protected int serviceTicketValiditySeconds = 60 * 30; //default 30 minutes.
...@@ -78,5 +83,27 @@ public class RedisOnlineTicketServices implements OnlineTicketServices { ...@@ -78,5 +83,27 @@ public class RedisOnlineTicketServices implements OnlineTicketServices {
} }
@Override
public void refresh(String ticketId,LocalTime refreshTime) {
OnlineTicket onlineTicket = get(ticketId);
onlineTicket.setTicketTime(refreshTime);
store(ticketId , onlineTicket);
}
@Override
public void refresh(String ticketId) {
OnlineTicket onlineTicket = get(ticketId);
LocalTime currentTime = LocalTime.now();
Duration duration = Duration.between(currentTime, onlineTicket.getTicketTime());
_logger.trace("OnlineTicket duration " + duration.getSeconds());
if(duration.getSeconds() > OnlineTicket.MAX_EXPIRY_DURATION) {
onlineTicket.setTicketTime(currentTime);
refresh(ticketId,currentTime);
}
}
} }
package org.maxkey.web.endpoint; package org.maxkey.authz.endpoint;
import org.maxkey.authn.online.OnlineTicket; import org.maxkey.authn.online.OnlineTicket;
import org.maxkey.authn.online.OnlineTicketServices; import org.maxkey.authn.online.OnlineTicketServices;
......
...@@ -135,7 +135,7 @@ public class CasAuthorizeEndpoint extends CasBaseAuthorizeEndpoint{ ...@@ -135,7 +135,7 @@ public class CasAuthorizeEndpoint extends CasBaseAuthorizeEndpoint{
} }
if(casDetails.getLogoutType()==LogoutType.BACK_CHANNEL) { if(casDetails.getLogoutType()==LogoutType.BACK_CHANNEL) {
String onlineTicketId = ((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket(); String onlineTicketId = ((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket().getTicketId();
OnlineTicket onlineTicket = onlineTicketServices.get(onlineTicketId); OnlineTicket onlineTicket = onlineTicketServices.get(onlineTicketId);
//set cas ticket as OnlineTicketId //set cas ticket as OnlineTicketId
casDetails.setOnlineTicket(ticket); casDetails.setOnlineTicket(ticket);
......
...@@ -67,7 +67,7 @@ public class CasDefaultAdapter extends AbstractAuthorizeAdapter { ...@@ -67,7 +67,7 @@ public class CasDefaultAdapter extends AbstractAuthorizeAdapter {
serviceResponseBuilder.setAttribute("departmentId", userInfo.getDepartmentId()); serviceResponseBuilder.setAttribute("departmentId", userInfo.getDepartmentId());
serviceResponseBuilder.setAttribute("workRegion",base64Attr(userInfo.getWorkRegion())); serviceResponseBuilder.setAttribute("workRegion",base64Attr(userInfo.getWorkRegion()));
serviceResponseBuilder.setAttribute(WebConstants.ONLINE_TICKET_NAME,authentication.getOnlineTicket()); serviceResponseBuilder.setAttribute(WebConstants.ONLINE_TICKET_NAME,authentication.getOnlineTicket().getTicketId());
return null; return null;
} }
......
...@@ -45,7 +45,7 @@ public class OAuthDefaultUserInfoAdapter extends AbstractAuthorizeAdapter { ...@@ -45,7 +45,7 @@ public class OAuthDefaultUserInfoAdapter extends AbstractAuthorizeAdapter {
beanMap.put("title", userInfo.getJobTitle()); beanMap.put("title", userInfo.getJobTitle());
beanMap.put("state", userInfo.getWorkRegion()); beanMap.put("state", userInfo.getWorkRegion());
beanMap.put("gender", userInfo.getGender()); beanMap.put("gender", userInfo.getGender());
beanMap.put(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket()); beanMap.put(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket().getTicketId());
String info= JsonUtils.object2Json(beanMap); String info= JsonUtils.object2Json(beanMap);
......
...@@ -176,7 +176,7 @@ public class UserInfoEndpoint { ...@@ -176,7 +176,7 @@ public class UserInfoEndpoint {
SigninPrincipal authentication = (SigninPrincipal)oAuth2Authentication.getUserAuthentication().getPrincipal(); SigninPrincipal authentication = (SigninPrincipal)oAuth2Authentication.getUserAuthentication().getPrincipal();
jwtClaimsSetBuilder.claim("sub", userInfo.getId()); jwtClaimsSetBuilder.claim("sub", userInfo.getId());
jwtClaimsSetBuilder.claim(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket()); jwtClaimsSetBuilder.claim(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket().getTicketId());
if(scopes.contains("profile")){ if(scopes.contains("profile")){
jwtClaimsSetBuilder.claim("name", userInfo.getUsername()); jwtClaimsSetBuilder.claim("name", userInfo.getUsername());
......
...@@ -73,7 +73,7 @@ public class AssertionEndpoint { ...@@ -73,7 +73,7 @@ public class AssertionEndpoint {
logger.debug("AuthnRequestInfo: {}", authnRequestInfo); logger.debug("AuthnRequestInfo: {}", authnRequestInfo);
HashMap <String,String>attributeMap=new HashMap<String,String>(); HashMap <String,String>attributeMap=new HashMap<String,String>();
attributeMap.put(WebConstants.ONLINE_TICKET_NAME, ((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket()); attributeMap.put(WebConstants.ONLINE_TICKET_NAME, ((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket().getTicketId());
//saml20Details //saml20Details
Response authResponse = authnResponseGenerator.generateAuthnResponse( Response authResponse = authnResponseGenerator.generateAuthnResponse(
......
...@@ -72,7 +72,7 @@ public class TokenBasedDefaultAdapter extends AbstractAuthorizeAdapter { ...@@ -72,7 +72,7 @@ public class TokenBasedDefaultAdapter extends AbstractAuthorizeAdapter {
} }
beanMap.put("displayName", userInfo.getDisplayName()); beanMap.put("displayName", userInfo.getDisplayName());
beanMap.put(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket()); beanMap.put(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket().getTicketId());
/* /*
* use UTC date time format * use UTC date time format
......
...@@ -20,6 +20,8 @@ package org.maxkey.web.endpoint; ...@@ -20,6 +20,8 @@ package org.maxkey.web.endpoint;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.maxkey.authn.SigninPrincipal;
import org.maxkey.authn.online.OnlineTicketServices;
import org.maxkey.authn.realm.AbstractAuthenticationRealm; import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.configuration.ApplicationConfig; import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.web.WebConstants; import org.maxkey.web.WebConstants;
...@@ -49,6 +51,10 @@ public class LogoutEndpoint { ...@@ -49,6 +51,10 @@ public class LogoutEndpoint {
@Autowired @Autowired
ApplicationConfig applicationConfig; ApplicationConfig applicationConfig;
@Autowired
@Qualifier("onlineTicketServices")
protected OnlineTicketServices onlineTicketServices;
@RequestMapping(value={"/logout"}) @RequestMapping(value={"/logout"})
public ModelAndView logout( public ModelAndView logout(
HttpServletRequest request, HttpServletRequest request,
...@@ -89,8 +95,10 @@ public class LogoutEndpoint { ...@@ -89,8 +95,10 @@ public class LogoutEndpoint {
_logger.debug("re Login URL : "+ reLoginUrl); _logger.debug("re Login URL : "+ reLoginUrl);
modelAndView.addObject("reloginUrl",reLoginUrl); modelAndView.addObject("reloginUrl",reLoginUrl);
onlineTicketServices.remove(((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket().getTicketId());
request.getSession().invalidate(); request.getSession().invalidate();
SecurityContextHolder.clearContext(); SecurityContextHolder.clearContext();
modelAndView.setViewName(viewName); modelAndView.setViewName(viewName);
return modelAndView; return modelAndView;
} }
......
...@@ -23,6 +23,9 @@ import javax.servlet.http.HttpServletRequest; ...@@ -23,6 +23,9 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.maxkey.authn.SavedRequestAwareAuthenticationSuccessHandler; import org.maxkey.authn.SavedRequestAwareAuthenticationSuccessHandler;
import org.maxkey.authn.SigninPrincipal;
import org.maxkey.authn.online.OnlineTicket;
import org.maxkey.authn.online.OnlineTicketServices;
import org.maxkey.configuration.ApplicationConfig; import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.constants.ConstantsPasswordSetType; import org.maxkey.constants.ConstantsPasswordSetType;
import org.maxkey.web.WebConstants; import org.maxkey.web.WebConstants;
...@@ -31,6 +34,7 @@ import org.slf4j.Logger; ...@@ -31,6 +34,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.security.web.savedrequest.SavedRequest;
...@@ -57,6 +61,10 @@ public class PermissionAdapter extends HandlerInterceptorAdapter { ...@@ -57,6 +61,10 @@ public class PermissionAdapter extends HandlerInterceptorAdapter {
SavedRequestAwareAuthenticationSuccessHandler savedRequestSuccessHandler; SavedRequestAwareAuthenticationSuccessHandler savedRequestSuccessHandler;
static ConcurrentHashMap<String, String> navigationsMap = null; static ConcurrentHashMap<String, String> navigationsMap = null;
@Autowired
@Qualifier("onlineTicketServices")
protected OnlineTicketServices onlineTicketServices;
/* /*
* 请求前处理 (non-Javadoc) * 请求前处理 (non-Javadoc)
...@@ -96,11 +104,12 @@ public class PermissionAdapter extends HandlerInterceptorAdapter { ...@@ -96,11 +104,12 @@ public class PermissionAdapter extends HandlerInterceptorAdapter {
} }
} }
Authentication authentication = WebContext.getAuthentication();
//save first protected url //save first protected url
SavedRequest firstSavedRequest = (SavedRequest)WebContext.getAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER); SavedRequest firstSavedRequest = (SavedRequest)WebContext.getAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER);
// 判断用户是否登录, 判断用户和角色,判断用户是否登录用户 // 判断用户是否登录, 判断用户和角色,判断用户是否登录用户
if (WebContext.getAuthentication() == null if (authentication == null
|| WebContext.getAuthentication().getAuthorities() == null) { || authentication.getAuthorities() == null) {
//保存未认证的请求信息 //保存未认证的请求信息
if(firstSavedRequest==null){ if(firstSavedRequest==null){
RequestCache requestCache = new HttpSessionRequestCache(); RequestCache requestCache = new HttpSessionRequestCache();
...@@ -119,14 +128,20 @@ public class PermissionAdapter extends HandlerInterceptorAdapter { ...@@ -119,14 +128,20 @@ public class PermissionAdapter extends HandlerInterceptorAdapter {
return false; return false;
} }
//认证完成,跳转到未认证请求 //认证完成,跳转到未认证请求
if(firstSavedRequest!=null) { if(firstSavedRequest!=null) {
savedRequestSuccessHandler.onAuthenticationSuccess(request, response, WebContext.getAuthentication()); savedRequestSuccessHandler.onAuthenticationSuccess(request, response, authentication);
WebContext.removeAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER); WebContext.removeAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER);
} }
boolean hasAccess = true; boolean hasAccess = true;
if(authentication.getPrincipal() instanceof SigninPrincipal) {
SigninPrincipal signinPrincipal = (SigninPrincipal)authentication.getPrincipal();
OnlineTicket onlineTicket = signinPrincipal.getOnlineTicket();
onlineTicketServices.refresh(onlineTicket.getTicketId());
}
/* /*
* boolean preHandler = super.preHandle(request, response, handler); * boolean preHandler = super.preHandle(request, response, handler);
* *
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册