If you integrate CAS 5.3 according to the front-end and back-end separation projects to achieve single sign-on

1. Obtain CAS5.3 project resources

GitHub - apereo/cas-overlay-template at 5.3

cas5.3.x still runs based on jdk8, and the next version 6.0.x will be based on jdk9. With the upgrade of cas version, the jdk version is getting higher and higher. There are instructions on the basic operating conditions of each version on the official website and github , select the version according to the actual situation.

Two. Tomcat deployment

  1. Use maven-package to make war package

2. Put the war package in the webapps directory of tomcat and start tomcat

3. Support HTTP protocol

  1. Modify the tomcat/webapps/cas/WEB-INF/classes/services/HTTPSandIMAPS-10000001.json file and add http support. The modified code is as follows.

  1. Modify the tomcat/webapps/cas/WEB-INF/classes/application.properties file

Add the following two lines

cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true

Comment out the following three lines

#server.ssl.key-store=file:/etc/cas/thekeystore
#server.ssl.key-store-password=changeit
#server.ssl.key-password=changeit
  1. Restart tomcat, visit the login page to log in

The cas default password is in the last line of the application.properties file

cas.authn.accept.users=casuser::Mellon

4. Front-end code

  1. Modify Navbar.vue to override the logout() method

    async logout() {
      this.$confirm('确定注销并退出系统吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$store.dispatch('LogOut').then(() => {
          if (!defaultSettings.casEnable) {
            location.href = this.$router.options.base + "/index";
          }
          //location.href = '/index';
        })
      }).catch(() => {});
    }
  1. Modify the permission.js file, copy the code and paste it to the red box, modify the address appropriately, and pay attention to the import package.

      if (!defaultSettings.casEnable) {
        next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      }
      // 开启cas
      if (defaultSettings.casEnable) {
        window.location.href = defaultSettings.casloginUrl // 否则全部重定向到登录页
      }
  1. Modify the settings.js file, add the following configuration, and modify the address appropriately. Before the service is the cas service address deployed earlier, and after the service is the backend service address of your own system

  /**
   * 开启cas
   */
  casEnable: false,
  /**
   * 单点登录url
   */
  casloginUrl:
    'http://cpmp.fulongai.cn/cas/login?service=http://192.168.2.154:8080',
  /**
   * 单点登出url
   */
  caslogoutUrl:
    'http://cpmp.fulongai.cn/cas/logout?service=http://192.168.2.154:8080'
  1. Modify the user.js file, replace the LogOut method, and pay attention to the import package.

    LogOut({ commit, state }) {
      return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_PERMISSIONS', [])
          commit('SET_PROJECT', {})
          sessionStorage.removeItem('dmp-projectId')
          removeToken()
          resolve()
          window.location.href = defaultSettings.caslogoutUrl
        }).catch(error => {
          reject(error)
        })
      })
    }
  1. Modify the request.js file and comment out the code in the red box

5. Backend code

  1. Add the CasUserDetailsService.java class under framework.web.service

package com.cpmplatform.framework.web.service;

import com.cpmplatform.common.core.domain.entity.SysUser;
import com.cpmplatform.common.core.domain.model.LoginUser;
import com.cpmplatform.common.enums.UserStatus;
import com.cpmplatform.common.exception.base.BaseException;
import com.cpmplatform.common.utils.StringUtils;
import com.cpmplatform.system.service.ISysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 * @author daixin
 * @version 1.0
 * @description: TODO
 * @date 2022/12/30 17:41
 */
@Service
public class CasUserDetailsService implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {

    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysPermissionService permissionService;

    public UserDetails createLoginUser(SysUser user) {
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    }

    @Override
    public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
        String username = token.getName();
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user)) {
            log.info("登录用户:{} 不存在.", username);
            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
        } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            log.info("登录用户:{} 已被删除.", username);
            throw new BaseException("对不起,您的账号:" + username + " 已被删除");
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户:{} 已被停用.", username);
            throw new BaseException("对不起,您的账号:" + username + " 已停用");
        }
        return createLoginUser(user);
    }
}
  1. Add the CasAuthenticationSuccessHandler.java class under framework.security.handle

package com.cpmplatform.framework.security.handle;

import com.cpmplatform.common.constant.Constants;
import com.cpmplatform.common.core.domain.model.LoginUser;
import com.cpmplatform.framework.config.properties.CasProperties;
import com.cpmplatform.framework.web.service.TokenService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author daixin
 * @version 1.0
 * @description: TODO
 * @date 2022/12/30 17:43
 */
@Service
public class CasAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    protected final Log logger = LogFactory.getLog(this.getClass());

    private RequestCache requestCache = new HttpSessionRequestCache();

    @Autowired
    private TokenService tokenService;

    @Autowired
    private CasProperties casProperties;

    // 令牌有效期(默认30分钟)
    @Value("${token.expireTime}")
    private int expireTime;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {
        String targetUrlParameter = getTargetUrlParameter();
        if (isAlwaysUseDefaultTargetUrl()
                || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
            requestCache.removeRequest(request, response);
            super.onAuthenticationSuccess(request, response, authentication);
            return;
        }
        clearAuthenticationAttributes(request);
        LoginUser userDetails = (LoginUser) authentication.getPrincipal();
        String token = tokenService.createToken(userDetails);
        //往Cookie中设置token
        Cookie casCookie = new Cookie(Constants.WEB_TOKEN_KEY, token);
        casCookie.setMaxAge(expireTime * 60);
        response.addCookie(casCookie);
        //设置后端认证成功标识
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute(Constants.CAS_TOKEN, token);
        //登录成功后跳转到前端登录页面,加了一个jwt参数
        getRedirectStrategy().sendRedirect(request, response, casProperties.getWebUrl()+"?jwt="+token);
    }
}
  1. Add CasProperties.java class under framework.config.properties

package com.cpmplatform.framework.config.properties;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author daixin
 * @version 1.0
 * @description: TODO
 * @date 2022/12/29 13:22
 */
@Data
@Component
public class CasProperties {
    @Value("${cas.server.host.url}")
    private String casServerUrl;

    @Value("${cas.server.host.login_url}")
    private String casServerLoginUrl;

    @Value("${cas.server.host.logout_url}")
    private String casServerLogoutUrl;

    @Value("${app.casEnable}")
    private boolean casEnable;

    @Value("${app.server.host.url}")
    private String appServerUrl;

    @Value("${app.login_url}")
    private String appLoginUrl;

    @Value("${app.logout_url}")
    private String appLogoutUrl;

    @Value("${app.web_url}")
    private String webUrl;

}
  1. LoginUser.java类,修改getAuthorities()方法的返回return new HashSet();

  1. 修改Constants.java类,增加代码

    /**
     * CAS登录成功后的后台标识
     */
    public static final String CAS_TOKEN = "cas_token";

    /**
     * CAS登录成功后的前台Cookie的Key
     */
    public static final String WEB_TOKEN_KEY = "Admin-Token";
  1. 修改application.yml文件,增加配置

#CAS
cas:
  server:
    host:
      #CAS服务地址
      url: http://cpmp.fulongai.cn/cas
      #CAS服务登录地址
      login_url: ${cas.server.host.url}/login
      #CAS服务登出地址
      logout_url: ${cas.server.host.url}/logout?service=${app.server.host.url}
# 应用访问地址
app:
  #开启cas
  casEnable: false
  server:
    host:
      #应用系统后端地址
      url: http://cpmp.fulongai.cn/cpmp/prod-api
  login_url: / #应用系统登录地址
  logout_url: /logout #应用系统登出地址
  #应用系统前端首页地址
  web_url: http://cpmp.fulongai.cn/cpmp/applicationManagement
  1. 修改SecurityConfig.java类

package com.cpmplatform.framework.config;

import com.cpmplatform.framework.config.properties.CasProperties;
import com.cpmplatform.framework.security.filter.JwtAuthenticationTokenFilter;
import com.cpmplatform.framework.security.handle.AuthenticationEntryPointImpl;
import com.cpmplatform.framework.security.handle.CasAuthenticationSuccessHandler;
import com.cpmplatform.framework.security.handle.LogoutSuccessHandlerImpl;
import com.cpmplatform.framework.web.service.CasUserDetailsService;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.filter.CorsFilter;
import com.cpmplatform.framework.config.properties.PermitAllUrlProperties;

/**
 * spring security配置
 * 
 * @author cpmplatform
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{

    @Autowired
    private CasProperties casProperties;

    @Autowired
    private CasUserDetailsService customUserDetailsService;

    @Autowired
    private CasAuthenticationSuccessHandler casAuthenticationSuccessHandler;

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 允许匿名访问的地址
     */
    @Autowired
    private PermitAllUrlProperties permitAllUrl;


    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        // 注解标记允许匿名访问的url
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
        permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());

        if (!casProperties.isCasEnable()) {
            httpSecurity
                    // CSRF禁用,因为不使用session
                    .csrf().disable()
                    // 基于token,所以不需要session
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                    // 过滤请求
                    .authorizeRequests()
                    // 对于登录login 验证码captchaImage 允许匿名访问
                    .antMatchers("/login", "/captchaImage").anonymous()
                    .antMatchers(
                            HttpMethod.GET,
                            "/*.html",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js"
                    ).permitAll()
                    .antMatchers("/profile/**").anonymous()
                    .antMatchers("/common/download**").anonymous()
                    .antMatchers("/common/download/resource**").anonymous()
                    .antMatchers("/swagger-ui.html").anonymous()
                    .antMatchers("/swagger-resources/**").anonymous()
                    .antMatchers("/webjars/**").anonymous()
                    .antMatchers("/*/api-docs").anonymous()
                    .antMatchers("/druid/**").anonymous()
                    // 除上面外的所有请求全部需要鉴权认证
                    .anyRequest().authenticated()
                    .and()
                    .headers().frameOptions().disable();
            httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
            // 添加JWT filter
            httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
            // 添加CORS filter
            httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
            httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
        }

        //开启cas
        if (casProperties.isCasEnable()) {
            httpSecurity
                    // CSRF禁用,因为不使用session
                    .csrf().disable()
                    // 基于token,所以不需要session
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                    // 过滤请求
                    .authorizeRequests()
                    // 对于登录login 验证码captchaImage 允许匿名访问
                    .antMatchers("/login","/logout", "/captchaImage").anonymous()
                    .antMatchers(
                            HttpMethod.GET,
                            "/*.html",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js"
                    ).permitAll()
                    .antMatchers("/profile/**").anonymous()
                    .antMatchers("/common/download**").anonymous()
                    .antMatchers("/common/download/resource**").anonymous()
                    .antMatchers("/swagger-ui.html").anonymous()
                    .antMatchers("/swagger-resources/**").anonymous()
                    .antMatchers("/webjars/**").anonymous()
                    .antMatchers("/*/api-docs").anonymous()
                    .antMatchers("/druid/**").anonymous()
                    // 除上面外的所有请求全部需要鉴权认证
                    .anyRequest().authenticated()
                    .and()
                    .headers().frameOptions().disable();
            //单点登录登出
            httpSecurity.logout().permitAll().logoutSuccessHandler(logoutSuccessHandler);
            // Custom JWT based security filter
            httpSecurity.addFilter(casAuthenticationFilter())
                    .addFilterBefore(authenticationTokenFilter, CasAuthenticationFilter.class)
                    //.addFilterBefore(casLogoutFilter(), LogoutFilter.class)
                    .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class).exceptionHandling()
                    //认证失败
                    .authenticationEntryPoint(casAuthenticationEntryPoint());

            // 添加CORS filter
            httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
            httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
            // disable page caching
            httpSecurity.headers().cacheControl();
        }
    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 定义认证用户信息获取来源,密码校验规则等
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        if (!casProperties.isCasEnable()) {
            auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
        }
        // cas
        if (casProperties.isCasEnable()) {
            super.configure(auth);
            auth.authenticationProvider(casAuthenticationProvider());
        }
    }

    /**
     * 认证的入口
     */
    @Bean
    public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
        CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
        casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
        casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
        return casAuthenticationEntryPoint;
    }

    /**
     * 指定service相关信息
     */
    @Bean
    public ServiceProperties serviceProperties() {
        ServiceProperties serviceProperties = new ServiceProperties();
        serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
        serviceProperties.setAuthenticateAllArtifacts(true);
        return serviceProperties;
    }

    /**
     * CAS认证过滤器
     */
    @Bean
    public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
        CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
        casAuthenticationFilter.setAuthenticationManager(authenticationManager());
        casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
        casAuthenticationFilter.setAuthenticationSuccessHandler(casAuthenticationSuccessHandler);
        return casAuthenticationFilter;
    }

    /**
     * cas 认证 Provider
     */
    @Bean
    public CasAuthenticationProvider casAuthenticationProvider() {
        CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
        casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService);
        casAuthenticationProvider.setServiceProperties(serviceProperties());
        casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
        casAuthenticationProvider.setKey("casAuthenticationProviderKey");
        return casAuthenticationProvider;
    }

    @Bean
    public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
        return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
    }

    /**
     * 单点登出过滤器
     */
    @Bean
    public SingleSignOutFilter singleSignOutFilter() {
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
        //singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());
        singleSignOutFilter.setIgnoreInitConfiguration(true);
        return singleSignOutFilter;
    }

    /**
     * 请求单点退出过滤器
     */
    @Bean
    public LogoutFilter casLogoutFilter() {
        LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(),
                new SecurityContextLogoutHandler());
        logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());
        return logoutFilter;
    }
}

六.自定义数据源

CAS应用到项目时,不可能一直使用默认账号登录,可连接项目数据库进行用户信息验证。

1.修改application.properties文件,添加数据源

cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
cas.authn.jdbc.query[0].url=jdbc:mysql://192.168.2.156:3306/cpmplatform?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
cas.authn.jdbc.query[0].user=cpmp
cas.authn.jdbc.query[0].password=123456
cas.authn.jdbc.query[0].sql=select password from sys_user where user_name=?
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].passwordEncoder.type=BCRYPT
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8

fieldPassword:数据库中密码字段列名

passwordEncoder.type:密码加密策略,支持NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2等多种配置,需与应用系统的加密策略一致,本项目使用的是强散列哈希加密,也就是BCRYPT

sql:密码查询语句,项目在实际应用中还可以增加条件,用户删除标志、用户状态等。

2.注释掉application.properties文件最后一行的默认用户名密码

#cas.authn.accept.users=casuser::Mellon

3.重启tomcat,使用系统用户登录,可登陆成功。

七.跨域问题

集成CAS过程中遇到的跨域问题,以及单点登录内嵌页面时的复杂跨域问题,单独整理了一篇,目前遇到的CORS报错都能解决:

https://blog.csdn.net/secretdaixin/article/details/129240863?spm=1001.2014.3001.5501

八.自定义登录页

本例中主题名称为cpmp,以下代码将以cpmp命名进行讲解。

  1. classes/static/themes目录下新建以主题名称命名的文件夹用于存放静态文件,css、js、图片等。

  1. classes目录下创建以主题名称命名的properties文件,本例文件名为cpmp.properties,用于配置主题所引用的资源的路径。前2~4行默认主题样式不能丢,否则页面会丢样式。下面的配置是步骤1创建的目录及文件。等号前的变量名称自定义即可,此变量会在步骤3创建的登录页面中引用。

# 系统默认主题样式
cas.standard.css.file = /css/cas.css
cas.javascript.file = /js/cas.js
cas.admin.css.file = /css/admin.css

# 自定义JS
login.js.element-ui = /themes/cpmp/js/element-ui.js
login.js.jquery = /themes/cpmp/js/jquery.min.js
login.js.cas = /themes/cpmp/js/cas.js

# 自定义CSS
login.css.element-ui = /themes/cpmp/css/element-ui.css
index.css.style = /themes/cpmp/css/cas.css

# 其它
login.img.path = /themes/cpmp/img
cas.page.title = cpmp
  1. classes/templates目录下新建以主题名称命名的文件夹用于存放登录页面,登录页面是一个固定名称的html文件,必须以casLoginView.html命名。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <link rel="stylesheet" th:href="@{${#themes.code('index.css.style')}}"/>
  <link rel="stylesheet" th:href="@{${#themes.code('login.css.elementui')}}"/>
</head>
<body>
  <!-- 第一套, 无th -->
  <div class="container">
    <div class="login">
      <h3>C A S 登录</h3>
      <form id="postForm" autocomplete="off" method="post" th:object="${credential}">
        <input type="hidden" name="execution" th:value="${flowExecutionKey}"/>
        <input type="hidden" name="_eventId" value="submit"/>
        <input type="hidden" name="geolocation"/>
        <i class="iconfont icon-man"></i>
        <input
          id="username"
          size="25"
          v-model.trim="username"
          tabindex="1"
          placeholder="请输入用户名"
          type="text"
          th:disabled="${guaEnabled}"
          th:field="*{username}"
          th:accesskey="#{screen.welcome.label.netid.accesskey}"
          autocomplete="off"
        />
        <i class="iconfont icon-suo"></i>
        <input
          type="password"
          id="password"
          size="25"
          tabindex="2"
          placeholder="请输入密码"
          th:accesskey="#{screen.welcome.label.password.accesskey}"
          th:field="*{password}"
          autocomplete="off"
        />
        <div th:if="${#fields.hasErrors('*')}">
          <span th:each="err : ${#fields.errors('*')}" th:utext="${err}" ></span>
        </div>

        <input
          name="submit"
          accesskey="l"
          th:value="#{screen.welcome.button.login}"
          type="submit"
          value="登录"
        />
      </form>
    </div>
  </div>

</body>
</html>
  1. 在classes/service目录下的服务注册文件中,为每个服务指定主题,以模板中默认的服务注册文件为例,也可以是自建的服务注册文件。

  1. 修改classes目录下的application.properties文件,增加代码用于指定默认主题

# 默认主题
cas.theme.defaultThemeName=cpmp
  1. 将文件发布到tomcat,重启tomcat,访问登录页面,主题配置成功。

Guess you like

Origin blog.csdn.net/secretdaixin/article/details/129690564