1、启动类里注释启用cas客户端的注解 (如果启用会使用默认的AuthenticationFilter)
2、引入依赖
<!--依赖cas 配置jar -->
<!-- 单点登录 -->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>2.3.0-GA</version>
</dependency>
<!-- Shiro 核心依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--单元测试的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jasig.cas.client/cas-client-integration-tomcat-common -->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-integration-tomcat-common</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
3、自定义过滤器MyAuthenticationFilter复制AuthenticationFilter只需修改doFilter方法即可
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
if (this.isRequestUrlExcluded(request)) {
this.logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
} else {
HttpSession session = request.getSession(false);
Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
filterChain.doFilter(request, response);
} else {
String serviceUrl = this.constructServiceUrl(request, response);
String ticket = this.retrieveTicketFromRequest(request);
boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
this.logger.debug("no ticket and no assertion found");
String modifiedServiceUrl;
if (this.gateway) {
this.logger.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
this.logger.debug("Constructed service url: {}", modifiedServiceUrl);
// String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
// this.logger.debug("redirecting to \"{}\"", urlToRedirectTo);
// this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
response.setContentType("application/json; charset=UTF-8");
out.println("{\"code\":\"403\",\"message\":\"请登陆!\"}");
} else {
filterChain.doFilter(request, response);
}
}
}
}
4、application.properties
# cas server settings
cas.server-url-prefix=https://xxx.com:8443/cas/
cas.server-login-url=https://xxx.com:8443/cas/login
cas.client-host-url=http://localhost:9100
cas.validation-type=cas
cas.use-session=true
# springboot server settings
server.port=9100
#自定义项目后台单点登录接口路径
client-host-url=http://127.0.0.1:9100/login/index
#自定义项目前台单点登录接口路径-单点登录平台也是配置此路径
adminPath=http://127.0.0.1:9100/index
cas-ignore-pattern=/logout|/login
#spring.mvc.servlet.load-on-startup=1
5、cas配置类
@Configuration
@Component
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;
@Value("${cas-ignore-pattern}")
private String casIgnorePattern;
/**
* @Author chenb2
* @Description 设置监听器
* @Date 14:24 2019/12/5
* @Param []
* @return org.springframework.boot.web.servlet.ServletListenerRegistrationBean
**/
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
ServletListenerRegistrationBean listenerRegistrationBean = new ServletListenerRegistrationBean();
listenerRegistrationBean.setListener(new SingleSignOutHttpSessionListener());
listenerRegistrationBean.setOrder(1);
return listenerRegistrationBean;
}
/**
* 该过滤器用于实现单点登出功能,当一个系统登出时,cas服务端会通知,各个应
* 用进行进行退出操作,该过滤器就是用来接收cas回调的请求,如果是前后端分离
* 应用,需要重写SingleSignOutFilter过滤器,按自已的业务规则去处理
*/
@Bean
public FilterRegistrationBean singleSignOutFilter() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
filterRegistration.setFilter(new SingleSignOutFilter());
filterRegistration.setEnabled(true);
filterRegistration.addUrlPatterns("/*");
filterRegistration.addInitParameter("casServerUrlPrefix", serverUrlPrefix);
filterRegistration.addInitParameter("serverName", clientHostUrl);
filterRegistration.setOrder(2);
return filterRegistration;
}
/**
* 授权过滤器
* @return
*/
@Bean
public FilterRegistrationBean filterAuthenticationRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyAuthenticationFilter());
Map<String,String> initParameters = new HashMap<String, String>();
initParameters.put("casServerLoginUrl",serverLoginUrl);
initParameters.put("serverName", clientHostUrl);
//忽略的url,"|"分隔多个url
initParameters.put("ignorePattern", casIgnorePattern);
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
/**
* 该过滤器用于单点登录功能,负责对Ticket的校验工作
* @return
*/
@Bean
public FilterRegistrationBean ValidationFilterRegistrationBean(){
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setOrder(5);
authenticationFilter.setFilter(new Cas30ProxyReceivingTicketValidationFilter());
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("casServerUrlPrefix", serverUrlPrefix);
initParameters.put("serverName", clientHostUrl);
authenticationFilter.setInitParameters(initParameters);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/*");
authenticationFilter.setUrlPatterns(urlPatterns);
return authenticationFilter;
}
/**
* 该过滤器用于单点登录功能 ,对HttpServletRequest请求包装, 可通过HttpServletRequest的getRemoteUser()方法获得登录用户的登录名
* @return
*/
@Bean
public FilterRegistrationBean casHttpServletRequestWrapperFilter(){
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(new HttpServletRequestWrapperFilter());
authenticationFilter.setOrder(6);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/*");
authenticationFilter.setUrlPatterns(urlPatterns);
return authenticationFilter;
}
}
6、Controller
import com.example.spring_boot_cas_demo.utils.CasServerUtil;
import com.example.spring_boot_cas_demo.utils.ResultUtil;
import com.example.spring_boot_cas_demo.utils.VerifyCode;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.client.util.AssertionHolder;
import org.jasig.cas.client.validation.Assertion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.spring_boot_cas_demo.utils.Result;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/login")
public class LoginController {
private static final Logger log = LoggerFactory.getLogger(LoginController.class);
@Value("${cas.server-login-url}")
private String serverLoginUrl;
@Value("${client-host-url}")
private String clientHostUrl;
@Value("${adminPath}")
private String adminPath;
@RequestMapping("/log")
public Result login(HttpServletRequest request, HttpServletResponse response, HttpSession httpSession){
log.info("进入单点登录的方法 in sso method");
//利用restful协议登录cas服务端
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(httpSession);
Map<String,String> map = new CasServerUtil().getUrl(username, password);
String strCookie = map.get("Cookie");
System.out.println(httpSession);
if(StringUtils.isNotEmpty(strCookie)){
String[] strArr = strCookie.split("; ");
for (int i=0 ;i<strArr.length;i++) {
if(strArr[i].contains("JSESSIONID")){
String sid = strArr[i].split("=")[1];
Cookie cookie=new Cookie("JSESSIONID", sid);
cookie.setPath("/");
cookie.setHttpOnly(true);
response.addCookie(cookie);
break;
}
}
}
return ResultUtil.success(map);
}
@RequestMapping("/index")
public Result index(HttpServletRequest request, HttpServletResponse response, HttpSession httpSession){
log.info("进入单点登录的方法 in sso method");
// 如果是单点登录模式
String ticket =request.getParameter("ticket");
Map<String, Object> map = new HashMap<>();
Cookie[] cookies = request.getCookies();
System.out.println("=======getCookies============"+request.getCookies());
System.out.println("============getCookies================="+cookies.length);
return ResultUtil.success(map);
}
7、工具类CasServerUtil
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CasServerUtil {
//登录地址的token
private String get_token_url = "";
//目标返回的服务器的url, 同访问的地址必须完全一致,不然就会报错。
private String taget_url = "";
private String ticket = "";
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public CasServerUtil(){
String serverUrl = "https://xxx.com:8443/cas/";
String serverB = "http://localhost:9100/login/index";
if (StringUtils.isNotBlank(serverUrl)) {
get_token_url = serverUrl + "v1/tickets/";
taget_url = serverB;
}
}
public CasServerUtil(String tgt,String taget_url) {
this.taget_url = taget_url;
this.ticket = getST(tgt);
}
/**
* 通过用户名密码获取tgt,并根据tgt获取ticket
* @param username
* @param password
* @return String
*/
public String getST(String username,String password){
String tgt = getTGT(username, password);
System.out.println("========tgt=========="+tgt);
if(StringUtils.isEmpty(tgt)){
return "";
}
return getST(tgt);
}
public Map<String,String> getUrl(String username,String password){
Map<String,String> map = new HashMap<>();
String tgt = getTGT(username, password);
if(StringUtils.isEmpty(tgt)){
return map;
}
String st = getST(tgt);
if(StringUtils.isEmpty(st)){
return map;
}
return response(st);
}
public Map<String,String> response(String st){
Map<String,String> map = new HashMap<>();
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(taget_url + "?ticket="+st);
String response = null;
try{
client.executeMethod(method);
response = method.getResponseBodyAsString();
Header header = method.getResponseHeader("Cookie");
if(header!=null){
map.put("Location",header.getValue());
}
header = method.getRequestHeader("Cookie");
System.out.println(method.getRequestHeaders());
if(header!=null){
map.put("Cookie",header.getValue());
}
System.out.println("=========response========"+response);
int status = method.getStatusCode();
switch (status){
case HttpStatus.SC_CREATED: // Created
Matcher matcher = Pattern.compile(".*action=\".*/(.*?)\".*").matcher(response);
if (matcher.matches()){
System.out.println(matcher.group(1));
}
break;
default:
break;
}
}catch (IOException e){
e.printStackTrace();
}finally{
method.releaseConnection();
}
return map;
}
/**
* 根据用户名、密码获取tgt
* @return String
*/
public String getTGT(String username,String password){
String tgt = "";
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(get_token_url);
method.setRequestBody(new NameValuePair[]{new NameValuePair("username", username), new NameValuePair("password", password)});
try{
client.executeMethod(method);
String response = method.getResponseBodyAsString();
System.out.println("=========tgt========"+response);
int status = method.getStatusCode();
switch (status){
case HttpStatus.SC_CREATED: // Created
Matcher matcher = Pattern.compile(".*action=\".*/(.*?)\".*").matcher(response);
if (matcher.matches()){
tgt = matcher.group(1);
}
break;
default:
break;
}
}catch (IOException e){
e.printStackTrace();
}finally{
method.releaseConnection();
}
return tgt;
}
/**
* 通过tgt获取st
* @param tgt
* @return String
*/
public String getST(String tgt){
String serviceTicket = "";
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(get_token_url + tgt + "/");
method.setRequestBody(new NameValuePair[]{new NameValuePair("service", taget_url)});
try {
client.executeMethod(method);
String response = method.getResponseBodyAsString();
System.out.println("=========st========"+response);
int status = method.getStatusCode();
switch (status){
case HttpStatus.SC_OK: // ok
serviceTicket = response.toString();
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}finally{
method.releaseConnection();
}
return serviceTicket;
}
}