单点登录CAS(一)搭建CAS - server服务器
CAS(一)搭建CAS - server服务器_Oumuv的博客-CSDN博客_cas server环境要求JDK 8+CAS 5.2tomcat 8+about CAScas document https://apereo.github.io/cas/5.2.x/index.htmlcas server 客户端模板下载 https://github.com/apereo/cas-overlay-template 步骤一、修改hosts文件,模拟跨域打开C:...https://blog.csdn.net/oumuv/article/details/83377945?spm=1001.2014.3001.5506CAS(四)基于Springboot搭建CAS-client,Springboot搭建CAS客户端
CAS(四)基于Springboot搭建CAS-client,Springboot搭建CAS客户端_Oumuv的博客-CSDN博客_cas springboot环境要求JDK 8+CAS 5.2tomcat 8+步骤一、搭建CAS服务器 -->CAS(一)搭建CAS - server服务器二、配置hosts,加入如下配置127.0.0.1 cas.server.com127.0.0.1 cas.client1.com三、搭建Springboot项目项目名为cas-clientB,项...简单总结:
1、pom依赖
<!-- 单点登录 -->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>2.3.0-GA</version>
</dependency>
2、application.properties配置
#单点登录前缀
cas.server-url-prefix=http://cas.server.com:8443/cas
#单点登录路径
cas.server-login-url=http://cas.server.com:8443/cas/login
cas.client-host-url=http://127.0.0.1:8088
cas.use-session=true
cas.validation-type=cas
server.port=8088
#自定义项目后台单点登录接口路径
client-host-url=http://127.0.0.1:8088/test/login/ssologin
#自定义项目前台单点登录接口路径-单点登录平台也是配置此路径
adminPath=http://127.0.0.1:9003/ssologin
3、CASAutoConfig配置类,配置需要匹配的url:
@Configuration
public class CASAutoConfig {
@Value("${cas.server-url-prefix}")
private String serverUrlPrefix;
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${cas.client-host-url}")
private String clientHostUrl;
/**
* 授权过滤器
* @return
*/
@Bean
public FilterRegistrationBean filterAuthenticationRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new AuthenticationFilter());
// 设定匹配的路径
registration.addUrlPatterns("/login/ssologin");
Map<String,String> initParameters = new HashMap<String, String>();
initParameters.put("casServerLoginUrl",serverLoginUrl);
initParameters.put("serverName", clientHostUrl);
//忽略的url,"|"分隔多个url
//initParameters.put("ignorePattern", "/logout/success|/index");
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
}
4、启动类加入开启cas client的注解
import net.unicon.cas.client.configuration.EnableCasClient;
@EnableCasClient//启用cas client
延用大神的图
到这里非前后端分离的springboot+cas就搭建好了。
接下来解决前后端分离,跨域的问题
问题记录
在前后端分离情况下,AuthenticationFilter重定向问题,导致前端发生跨域
(1)描述
cas前后端不分离的情况下是能够直接跳转的,然而前后端分离后,前端ajax访问后端在经过AuthenticationFilter时,验证未登录会重定向到CAS登录,导致前端发生跨域问题
(2)解决思路
在AuthenticationFilter中不进行重定向,验证未登录就直接返回一个错误状态码;由前端获取到状态码后进行判断,再跳转到CAS登录地址
原先的 AuthenticationFilter
AuthenticationFilter 里的 doFilter方法
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpSession session = request.getSession(false);
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
if (assertion != null) {
filterChain.doFilter(request, response);
return;
}
final String serviceUrl = constructServiceUrl(request, response);
final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
filterChain.doFilter(request, response);
return;
}
final String modifiedServiceUrl;
log.debug("no ticket and no assertion found");
if (this.gateway) {
log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (log.isDebugEnabled()) {
log.debug("Constructed service url: " + modifiedServiceUrl);
}
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (log.isDebugEnabled()) {
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
}
在本地重写原先的 AuthenticationFilter,doFilter方法,对就是这么霸气。
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
}
LoginController
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${client-host-url}")
private String clientHostUrl;
@Value("${adminPath}")
private String adminPath;
@RequestMapping(value = "/login/ssologin", method = RequestMethod.GET)
public R ssoLogin(HttpSession session, HttpServletRequest request, HttpServletResponse response, Model model) {
log.info("进入单点登录的方法 in sso method");
// 如果是单点登录模式
String ticket =request.getParameter("ticket");
Assertion assertion = AssertionHolder.getAssertion();
log.info("------------assertion:"+assertion);
if(ticket==null)ticket=UUID.randomUUID().toString();
if (assertion!=null) {
Map<String, Object> map = new HashMap<>();
String redirectUrl= request.getParameter("redirectUrl");
log.debug("redirectUrl: " + redirectUrl);
try {
if(redirectUrl != null){
// 单点登录成功后,重定向到前台url
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.sendRedirect(redirectUrl);
} else {
log.debug("Successfully authenticated user: " + assertion.getPrincipal().getName());
String userid = assertion.getPrincipal().getName();
SysUser user = getsysUser();//数据库查询用户
if(ObjectUtils.isEmpty(user)) {
throw new CEException("该账户不存在业务系统,请确认!");
}
map.put("result", user);
}
} catch (IOException e) {
e.printStackTrace();
}
return R.ok().put("data", map);
}
// serverLoginUrl+"?service="+clientHostUrl+"?redirectUrl="+adminPath
return R.ok("进行平台登录!").put("code", "401").put("serverLoginUrl", serverLoginUrl).put("service",clientHostUrl).put("redirectUrl",adminPath);
}
react前端代码
// 单点登录用户未登录,打开认证中心登录地址并将前端地址作为参数传回,以便登录成功跳转到前端页面
if(res.code&&res.code=='401'){
console.log('res.code', res.code);
// serverLoginUrl+"?service="+clientHostUrl+"?redirectUrl="+adminPath
let serverLoginUrl = res.serverLoginUrl;
let service = res.service;
let redirectUrl = res.redirectUrl;
// 这里保存返回单点登录的地址
localStorage.setItem("serverLoginUrl",serverLoginUrl);
window.location.href = serverLoginUrl+"?service="+service+"?redirectUrl="+redirectUrl;
// window.location.href = 'http://cas.server.com:8443/cas/login?service=http://127.0.0.1:8088/test/login/ssologin?redirectUrl=http://127.0.0.1:9003/ssologin'
}
简单复盘
1.第一次登录时,Assertion 为null,返回401code,并将各个URL返回。
2.前端将各个URL拼接,redirectUrl是登录成功后重定向的地址。
3.再次打开前台单点登录地址时,已登录成功,Assertion可以获取具体的用户。
4.根据用户到数据库查询权限角色,返回和登录一致的内容。