Bootstrap

SpringBoot整合Cas

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;
    }
}

;