cas单点登录

This commit is contained in:
huangweixiong 2022-06-30 09:41:38 +08:00
parent d9222f25e1
commit 214bf4bc61
7 changed files with 350 additions and 78 deletions

View File

@ -293,6 +293,13 @@
<version>${ffmpeg.version}-${javacv.version}</version>
<classifier>${system.linux-x86_64}</classifier>
</dependency>
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>2.0.0-GA</version>
</dependency>
</dependencies>
<build>

View File

@ -1,4 +1,100 @@
package io.renren.modules.security.oauth2;
public class CasSSOValidator {
import cn.hutool.core.util.URLUtil;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.json.Cas30JsonServiceTicketValidator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
@ConditionalOnProperty(prefix = "sso", name = "mode", havingValue = "cas")
public class CasSSOValidator implements SSOValidator {
@Value("${cas.server-url-prefix}")
private String serverUrlPrefix;
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${cas.client-host-url}")
private String clientHostUrl;
private Cas30JsonServiceTicketValidator ticketValidator;
@PostConstruct
public void init(){
ticketValidator = new Cas30JsonServiceTicketValidator(serverUrlPrefix);
}
@Override
public String validatePrincipal(String requestURL) {
String ticket = getParema(requestURL, "ticket");
try {
Assertion validate = ticketValidator.validate(ticket, removeCreditParame(requestURL));
if (validate != null) return validate.getPrincipal().getName();
} catch (TicketValidationException e) {
e.printStackTrace();
return null;
}
return null;
}
@Override
public boolean hasCrediteInCallBackUrl(String url) {
return url != null && url.indexOf("ticket=") > -1;
}
@Override
public String removeCreditParame(String url) {
try {
URL matchUrl = new URL(url);
String query = matchUrl.getQuery();
StringBuilder stringBuilder = new StringBuilder();
if (query == null){
return url;
}
String[] split = query.split("&");
for (String s : split) {
if (s.startsWith("ticket")) continue;
stringBuilder.append(s);
stringBuilder.append("&");
}
String newQuery = stringBuilder.toString();
if (newQuery.endsWith("&")) newQuery = newQuery.substring(0, newQuery.length()-1);
return url.replace(StringUtils.isBlank(newQuery) ? "?"+query:query, newQuery);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return url;
}
@Override
public String getLoginUrl(String callBackUrl) {
return serverLoginUrl + "?service=" + URLEncoder.encode(removeCreditParame(callBackUrl));
}
private static String getParema(String urlStr, String field) {
String result = "";
Pattern pXM = Pattern.compile(field + "=([^&|^#]*)");
Matcher mXM = pXM.matcher(urlStr);
while (mXM.find()) {
result = mXM.group(1);
}
return result;
}
}

View File

@ -19,6 +19,7 @@ import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
@ -42,8 +43,7 @@ import java.util.Map;
@Scope("prototype")
public class Oauth2Filter extends AuthenticatingFilter {
@Autowired
private YaweiSSOProperties yaweiSSOProperties;
@Autowired
private SysUserTokenService sysUserTokenService;
@ -51,8 +51,8 @@ public class Oauth2Filter extends AuthenticatingFilter {
@Autowired
private SysUserDao sysUserDao;
@Value("${yawei.enable}")
private Boolean yaweiEnable;
@Autowired
private SSOValidator ssoValidator;
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
@ -93,11 +93,9 @@ public class Oauth2Filter extends AuthenticatingFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (yaweiEnable) {
return yaweiHandle((HttpServletRequest) request, (HttpServletResponse) response);
if (ssoValidator != null) {
return ssoHandle((HttpServletRequest) request, (HttpServletResponse) response);
}else {
String requesturi = ((HttpServletRequest) request).getHeader("REQUESTURI");
((HttpServletResponse)response).addHeader("REDIRECT", "/#/login");
}
@ -167,88 +165,49 @@ public class Oauth2Filter extends AuthenticatingFilter {
return token;
}
private boolean yaweiHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
private boolean ssoHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取当前请求的url
String requestUri = request.getHeader("REQUESTURI");
if (requestUri == null) {
requestUri = request.getRequestURI();
}
String strResponse = request.getParameter(yaweiSSOProperties.getSsoKey());
if (strResponse == null && requestUri != null && requestUri.indexOf(yaweiSSOProperties.getSsoKey()) > 0) {
String ssoMatchKey = yaweiSSOProperties.getSsoKey() + "=";
int startIndex = requestUri.indexOf(ssoMatchKey) + ssoMatchKey.length();
int indexOf = requestUri.indexOf("&", startIndex);
strResponse = indexOf > 0 ? requestUri.substring(startIndex, indexOf) : requestUri.substring(startIndex);
if (!ssoValidator.hasCrediteInCallBackUrl(requestUri)) {
redirectToUrl(ssoValidator.getLoginUrl(requestUri), response);
return false;
}
if (org.apache.commons.lang.StringUtils.isEmpty(strResponse)) {
TicketManager tm = new TicketManager();
if (!tm.LoadTicket(request)) {
redirectToYaweiLogin(request, response);
return false;
}
} else {
// 如果服务器端通过认证后会返回后执行改操作然后写入cookie
SSOResponse ssoResp = new SSOResponse(strResponse);
TicketManager tm = ssoResp.CreatePSOTicket();
if (tm == null) {
redirectToYaweiLogin(request, response);
return false;
} else {
//认证通过
LambdaQueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<SysUserEntity>().lambda()
.eq(SysUserEntity::getUsername, tm.getUserID());
SysUserEntity sysUserEntity = sysUserDao.selectOne(queryWrapper);
if (sysUserEntity != null) {
String currentToken = getRequestToken((HttpServletRequest) request);
HttpServletResponse httpresponse = (HttpServletResponse) response;
if (StringUtils.isBlank(currentToken)) {
Result<Map> result = sysUserTokenService.createToken(sysUserEntity.getId());
Object token = result.getData().get(Constant.TOKEN_HEADER);
currentToken = (String) token;
Cookie cookie = new Cookie(Constant.TOKEN_HEADER, currentToken);
cookie.setPath("/");
httpresponse.addCookie(cookie);
httpresponse.addHeader(Constant.TOKEN_HEADER, currentToken);
String yaweiToken = yaweiSSOProperties.getSsoKey() + "=" + strResponse;
if (requestUri.indexOf(yaweiToken) > 0) {
requestUri = requestUri.replace(yaweiToken, "");
if (requestUri.endsWith("?")) {
requestUri = requestUri.substring(0,requestUri.length() -1);
}
}
httpresponse.addHeader("REDIRECT", requestUri);
}
String principal = ssoValidator.validatePrincipal(requestUri);
if (principal != null){
//认证通过
LambdaQueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<SysUserEntity>().lambda()
.eq(SysUserEntity::getUsername, principal);
SysUserEntity sysUserEntity = sysUserDao.selectOne(queryWrapper);
if (sysUserEntity != null) {
request.setAttribute(Constant.TOKEN_HEADER, currentToken);
return executeLogin(request, response);
}else {
send401Error(response, "未找到相关用户");
}
Result<Map> result = sysUserTokenService.createToken(sysUserEntity.getId());
Object token = result.getData().get(Constant.TOKEN_HEADER);
String currentToken = (String) token;
Cookie cookie = new Cookie(Constant.TOKEN_HEADER, currentToken);
cookie.setPath("/");
response.addCookie(cookie);
response.addHeader(Constant.TOKEN_HEADER, currentToken);
//去掉凭证参数
String removeCreditParame = ssoValidator.removeCreditParame(requestUri);
response.addHeader("REDIRECT", removeCreditParame);
request.setAttribute(Constant.TOKEN_HEADER, currentToken);
return executeLogin(request, response);
}else {
send401Error(response, "未找到相关用户");
}
}
redirectToUrl(ssoValidator.getLoginUrl(requestUri), response);
return false;
}
private void redirectToYaweiLogin(HttpServletRequest request, HttpServletResponse response) throws IOException, IllegalAccessException, NoSuchFieldException {
String requestUri = request.getHeader("REQUESTURI");
if (requestUri == null) {
requestUri = request.getRequestURI();
}
PSORequest psoRequest = new PSORequest(request);
//不建新类了直接反射解决
Field returnUrl = psoRequest.getClass().getDeclaredField("returnUrl");
returnUrl.setAccessible(true);
returnUrl.set(psoRequest, requestUri);
String requeststr = psoRequest.CreateHash();
String keeperUrl = yaweiSSOProperties.getKeeperUrl();
keeperUrl = keeperUrl + "?" + yaweiSSOProperties.getSsoKey() + "="
+ URLEncoder.encode(requeststr, "UTF-8");
response.addHeader("REDIRECT", keeperUrl);
private void redirectToUrl(String url, HttpServletResponse response) throws IOException {
response.addHeader("REDIRECT", url);
response.setStatus(HttpStatus.SC_UNAUTHORIZED);
response.getOutputStream().write(HttpStatus.SC_UNAUTHORIZED);
}

View File

@ -1,4 +1,14 @@
package io.renren.modules.security.oauth2;
import javax.servlet.http.HttpServletRequest;
public interface SSOValidator {
String validatePrincipal(String requestURL);
boolean hasCrediteInCallBackUrl(String url);
String removeCreditParame(String url);
String getLoginUrl(String callBackUrl);
}

View File

@ -1,4 +1,90 @@
package io.renren.modules.security.oauth2;
public class YaweiSSOValidator {
import com.yawei.pso.DateHelper;
import com.yawei.pso.PSORequest;
import com.yawei.pso.SSOResponse;
import com.yawei.pso.TicketManager;
import com.yawei.pso.security.Encrypter;
import io.renren.common.interceptor.YaweiSSOProperties;
import org.apache.catalina.connector.Request;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.Principal;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
@Component
@ConditionalOnProperty(prefix = "sso", name = "mode", havingValue = "yawei")
public class YaweiSSOValidator implements SSOValidator {
@Autowired
private YaweiSSOProperties yaweiSSOProperties;
@Override
public String validatePrincipal(String requestURL) {
String strResponse = getSSOToken(requestURL);
SSOResponse ssoResp = new SSOResponse(strResponse);
TicketManager tm = ssoResp.CreatePSOTicket();
if (tm != null){
return tm.getUserID();
}
return null;
}
@Override
public boolean hasCrediteInCallBackUrl(String url) {
return StringUtils.isNotBlank(getSSOToken(url));
}
@Override
public String removeCreditParame(String url) {
String yaweiToken = yaweiSSOProperties.getSsoKey() + "=" + getSSOToken(url);
if (url.indexOf(yaweiToken) > 0) {
url = url.replace(yaweiToken, "");
if (url.endsWith("?")) {
url = url.substring(0,url.length() -1);
}
}
return url;
}
@Override
public String getLoginUrl(String callBackUrl) {
Encrypter en = new Encrypter("qP70966AcZCQyXR+3P1mfjmqqxdkagom", "FnZ+19kJbQ8=");
String requeststr = "PSOSite$" + en.EncryptString(DateHelper.getCurrentStrTime() +
"|" + callBackUrl + "||");
String keeperUrl = yaweiSSOProperties.getKeeperUrl();
try {
keeperUrl = keeperUrl + "?" + yaweiSSOProperties.getSsoKey() + "="
+ URLEncoder.encode(requeststr, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return keeperUrl;
}
private String getSSOToken(String url){
String ssoMatchKey = yaweiSSOProperties.getSsoKey() + "=";
int startIndex = url.indexOf(ssoMatchKey) + ssoMatchKey.length();
if (startIndex < ssoMatchKey.length()) return null;
int indexOf = url.indexOf("&", startIndex);
return indexOf > 0 ? url.substring(startIndex, indexOf) : url.substring(startIndex);
}
}

View File

@ -112,3 +112,17 @@ zsk:
version: 1.0
methodId: jirdGetInfoByCatalog
catalogIds: c0645e03fb7e4cf3842e9ceedd8ab998,f49561afc7204f008c4bb3cd821eb6ba
sso:
mode: yawei # 取值 yawei,cas
cas:
server-url-prefix: http://10.134.135.81:11188/cas
server-login-url: http://10.134.135.81:11188/cas/login
client-host-url: http://localhost:9999/#/
use-session: false
validation-type: cas3
# 前端地址,用于退出登录后的重定向
front:
url: http://10.16.16.159:4444

View File

@ -1,4 +1,104 @@
package io.renren;
import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DataResourceTest {
@NoArgsConstructor
@Data
@ContentRowHeight(20)
@HeadRowHeight(20)
@ColumnWidth(25)
public static class Entity {
@ExcelProperty(value = "zyname", index = 0)
@JsonProperty("zyname")
private String zyname;
@JsonProperty("sjcczl")
@ExcelProperty(value = "sjcczl", index = 1)
private Double sjcczl;
@JsonProperty("zycode")
@ExcelProperty(value = "zycode", index = 2)
private String zycode;
@JsonProperty("ygxjghjls")
@ExcelProperty(value = "ygxjghjls", index = 3)
private Double ygxjghjls;
@JsonProperty("jghxxjlzs")
@ExcelProperty(value = "jghxxjlzs", index = 4)
private Double jghxxjlzs;
@JsonProperty("neibukeshi")
@ExcelProperty(value = "neibukeshi", index = 5)
private String neibukeshi;
@JsonProperty("xgxt")
@ExcelProperty(value = "xgxt", index = 6)
private String xgxt;
@JsonProperty("ygxdsjccl")
@ExcelProperty(value = "ygxdsjccl", index = 7)
private Double ygxdsjccl;
@JsonProperty("zygszl")
@ExcelProperty(value = "zygszl", index = 8)
private String zygszl;
@JsonProperty("ykfjghjls")
@ExcelProperty(value = "ykfjghjls", index = 9)
private Double ykfjghjls;
@JsonProperty("syqk")
@ExcelProperty(value = "syqk", index = 10)
private Integer syqk;
@ExcelProperty(value = "zyformat", index = 11)
@JsonProperty("zyformat")
private String zyformat;
@ExcelProperty(value = "guid", index = 12)
@JsonProperty("guid")
private String guid;
@ExcelProperty(value = "TGBM", index = 13)
@JsonProperty("TGBM")
private String tgbm;
@ExcelProperty(value = "ykfdsjccl", index = 14)
@JsonProperty("ykfdsjccl")
private Double ykfdsjccl;
}
@Test
public void test(){
String string = FileUtil.readUtf8String("/Users/huangweixiong/Downloads/data.json");
List<Entity> entities = JSONArray.parseArray(string, Entity.class);
EasyExcel.write("/Users/huangweixiong/Downloads/dataResource.xlsx")
.sheet(0)
.head(Entity.class)
.doWrite(entities);
}
}