This commit is contained in:
winLsy
2018-01-17 22:17:50 +08:00
parent 2d359bf8db
commit e067c8ea2c
10 changed files with 274 additions and 21 deletions
@@ -0,0 +1,39 @@
/**
*
*/
package com.micro.fast.security.browser.config;
import com.micro.fast.security.browser.session.MsExpiredSessionStrategy;
import com.micro.fast.security.browser.session.MsInvalidSessionStrategy;
import com.micro.fast.security.core.master.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
/**
*
* @author lsy
*/
@Configuration
public class BrowserSecurityBeanConfig {
@Autowired
private SecurityProperties securityProperties;
@Bean
@ConditionalOnMissingBean(InvalidSessionStrategy.class)
public InvalidSessionStrategy invalidSessionStrategy(){
return new MsInvalidSessionStrategy(securityProperties.getSession().getSessionInvalidUrl());
}
@Bean
@ConditionalOnMissingBean(SessionInformationExpiredStrategy.class)
public SessionInformationExpiredStrategy sessionInformationExpiredStrategy(){
return new MsExpiredSessionStrategy(securityProperties.getSession().getSessionInvalidUrl());
}
}
@@ -1,6 +1,7 @@
package com.micro.fast.security.browser.config;
import com.micro.fast.security.browser.session.MsExpiredSessionStrategy;
import com.micro.fast.security.browser.session.MsInvalidSessionStrategy;
import com.micro.fast.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.micro.fast.security.core.master.SecurityConstants;
import com.micro.fast.security.core.master.SecurityProperties;
@@ -19,9 +20,10 @@ import org.springframework.security.web.authentication.AuthenticationSuccessHand
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.social.security.SpringSocialConfigurer;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
@@ -45,6 +47,13 @@ public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
//todo 待优化,不唯一,应从启动参数中获取
public static final String DRUID = "/druid/*";
@Autowired
private InvalidSessionStrategy invalidSessionStrategy;
@Autowired
private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;
/**
* 注入身份认证框架配置参数对象
*/
@@ -121,14 +130,14 @@ public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
.and()
// session管理的配置
.sessionManagement()
//定义session过期的时候处理的url
.invalidSessionUrl("/session/invalid")
//session过期处理的类
.invalidSessionStrategy(invalidSessionStrategy)
//session存在的最大数量
.maximumSessions(1)
//设置session被替换掉时处理逻辑
.expiredSessionStrategy(new MsExpiredSessionStrategy())
//设置不允许第二个用户登录,不设置这句话的话,会替换掉上一个登录用户
.maxSessionsPreventsLogin(true)
.maximumSessions(securityProperties.getSession().getMaximumSessions())
//设置是否允许第二个用户登录,如果不阻止的话,会替换掉上一个登录用户
.maxSessionsPreventsLogin(securityProperties.getSession().isMaxSessionPreventsLogin())
//设置session被替换掉时处理逻辑,是定义session过期的时候处理的url
.expiredSessionStrategy(sessionInformationExpiredStrategy)
.and()
.and()
.authorizeRequests()//下面是权限配置
@@ -7,7 +7,6 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
@@ -30,6 +29,7 @@ import java.util.Map;
/**
* 自定义登录认证处理方式,当触发登录认证的时候跳转到这里
* @author lsy
*/
@RestController
public class BrowserSecurityController {
@@ -0,0 +1,97 @@
package com.micro.fast.security.browser.session;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.micro.fast.security.core.reponse.ServerResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author lsy
*/
public class AbstractSessionStrategy {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 跳转的url
*/
private String destinationUrl;
/**
* 重定向策略
*/
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
/**
* 跳转前是否创建新的session
*/
private boolean createNewSession = true;
private ObjectMapper objectMapper = new ObjectMapper();
/**
*
* @param invalidSessionUrl
*/
public AbstractSessionStrategy(String invalidSessionUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
this.destinationUrl = invalidSessionUrl;
}
protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException {
if (createNewSession) {
request.getSession();
}
String sourceUrl = request.getRequestURI();
String targetUrl;
if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
targetUrl = destinationUrl+".html";
logger.info("session失效,跳转到"+targetUrl);
redirectStrategy.sendRedirect(request, response, targetUrl);
}else{
String message = "session已失效";
if(isConcurrency()){
message = message + ",有可能是并发登录导致的";
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(ServerResponse.errorMsg(message)));
}
}
/**
* session失效是否是并发导致的
* @return
*/
protected boolean isConcurrency() {
return false;
}
/**
* Determines whether a new session should be created before redirecting (to
* avoid possible looping issues where the same session ID is sent with the
* redirected request). Alternatively, ensure that the configured URL does
* not pass through the {@code SessionManagementFilter}.
*
* @param createNewSession
* defaults to {@code true}.
*/
public void setCreateNewSession(boolean createNewSession) {
this.createNewSession = createNewSession;
}
}
@@ -1,19 +1,35 @@
/**
*
*/
package com.micro.fast.security.browser.session;
import java.io.IOException;
import javax.servlet.ServletException;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import javax.servlet.ServletException;
import java.io.IOException;
/**
* 处理session顶替的策略
* @author lsy
* @author zhailiang
*
*/
public class MsExpiredSessionStrategy implements SessionInformationExpiredStrategy {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException {
sessionInformationExpiredEvent.getResponse().setContentType("application/json;charset=UTF-8");
sessionInformationExpiredEvent.getResponse().getWriter().write("并发登录");
}
public class MsExpiredSessionStrategy extends AbstractSessionStrategy implements SessionInformationExpiredStrategy {
public MsExpiredSessionStrategy(String invalidSessionUrl) {
super(invalidSessionUrl);
}
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
onSessionInvalid(event.getRequest(), event.getResponse());
}
@Override
protected boolean isConcurrency() {
return true;
}
}
@@ -0,0 +1,30 @@
/**
*
*/
package com.micro.fast.security.browser.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.session.InvalidSessionStrategy;
/**
* @author zhailiang
*
*/
public class MsInvalidSessionStrategy extends AbstractSessionStrategy implements InvalidSessionStrategy {
public MsInvalidSessionStrategy(String invalidSessionUrl) {
super(invalidSessionUrl);
}
@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
onSessionInvalid(request, response);
}
}
@@ -34,7 +34,7 @@ weChat 第三方登录
- `ms.security.social.weChat.appId` 类比qq登录
- `ms.security.social.weChat.appSecret` 类比qq登录
- `ms.security.social.weChat.providerId` 类比qq登录
绑定,解绑第三方用户
### 绑定,解绑第三方用户
- 查询已绑定的用户,请求`/connect`接口即可,要求当前登录的用户放入session中的是SocialUser的对象,能获取到getId
- 绑定用户就是发起post请求`/connect/providerId`即可.可以使用自定义名称为`qqConnectedView`或`weChatConnectedView`的bean来自定义视图
- 解除绑定的时候,发送delete请求`/connect/providerId`删除社交登录的信息即可。返回的视图和绑定的时候使用相同的视图,在视图里面做逻辑判断
@@ -36,4 +36,9 @@ public interface SecurityConstants {
*/
String GET_VALIDATE_CODE_PREFIX = "/code/";
/**
* session失效的处理地址
*/
String DEFAULT_SESSION_INVALID_URL = "/ms-session-invalid.html";
}
@@ -28,6 +28,16 @@ public class SecurityProperties {
private SocialProperties social = new SocialProperties();
private SessionProperties session = new SessionProperties();
public SessionProperties getSession() {
return session;
}
public void setSession(SessionProperties session) {
this.session = session;
}
public Boolean getCreateRememberTable() {
return createRememberTable;
}
@@ -0,0 +1,47 @@
package com.micro.fast.security.core.master;
/**
* session处理的配置
* @author lsy
*/
public class SessionProperties {
/**
* 同一个系统中的最大session数,默认1
*/
private int maximumSessions = 1;
/**
* 达到最大session时,是否阻止新的登录请求,默认为false,不阻止,新的登录将老的登录
* 失效掉
*/
private boolean maxSessionPreventsLogin = false;
/**
* session失效的时候跳转的地址
*/
private String sessionInvalidUrl = SecurityConstants.DEFAULT_SESSION_INVALID_URL;
public int getMaximumSessions() {
return maximumSessions;
}
public void setMaximumSessions(int maximumSessions) {
this.maximumSessions = maximumSessions;
}
public boolean isMaxSessionPreventsLogin() {
return maxSessionPreventsLogin;
}
public void setMaxSessionPreventsLogin(boolean maxSessionPreventsLogin) {
this.maxSessionPreventsLogin = maxSessionPreventsLogin;
}
public String getSessionInvalidUrl() {
return sessionInvalidUrl;
}
public void setSessionInvalidUrl(String sessionInvalidUrl) {
this.sessionInvalidUrl = sessionInvalidUrl;
}
}