位置:
auth
模块中添加cas
依赖
<!-- Cas Core -->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.6.4</version>
</dependency>
位置:
nacos
中的ruoyi-auth-dev.yml
文件(或auth
模块下bootstrap.yml
文件)
增加cas
配置
cas:
enable: true
server:
url:
prefix: http://127.0.0.1:8888/cas
login: http://127.0.0.1:8888/cas/login
client:
url: http://127.0.0.1:8080/auth
位置:
common-core
模块下的com/ruoyi/common/core/constant/Constants.java
增加CAS
认证成功标识
/**
* CAS登录成功后的后台标识
**/
public static final String CAS_TOKEN = "cas_token";
/**
* CAS登录成功后的前台Cookie的Key
**/
public static final String WEB_TOKEN_KEY = "Cloud-Token";
/**
* CAS登录成功后的前台Cookie的Expires-In
**/
public static final String WEB_TOKEN_EXPIRES = "Cloud-Expires-In";
位置:在
auth
模块中添加CasProperties.java
文件
获取CAS
配置信息
package com.ruoyi.auth.cas.config.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
@Configuration
@RefreshScope
public class CasProperties {
@Value("{cas.enable}")
private Boolean enabled;
@Value("{cas.server.url.prefix}")
private String casServerUrlPrefix;
@Value("{cas.server.url.login}")
private String casServerLoginUrl;
@Value("{cas.client.url}")
private String serverName;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public String getCasServerUrlPrefix() {
return casServerUrlPrefix;
}
public void setCasServerUrlPrefix(String casServerUrlPrefix) {
this.casServerUrlPrefix = casServerUrlPrefix;
}
public String getCasServerLoginUrl() {
return casServerLoginUrl;
}
public void setCasServerLoginUrl(String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
}
位置:
auth
模块中添加NoCasFilter.java
文件
未启用CAS
时直接放行
package com.ruoyi.auth.cas.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @author ruoyi
**/
public final class NoCasFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(request, response);
}
}
在
auth
模块中添加CustomSessionMappingStorage.java
文件
实现单点登出
package com.ruoyi.auth.cas.storage;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.security.service.TokenService;
import org.apache.catalina.session.StandardSessionFacade;
import org.jasig.cas.client.session.SessionMappingStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
/**
* @author ruoyi
**/
@Component
public class CustomSessionMappingStorage implements SessionMappingStorage {
private final Map<String, HttpSession> MANAGED_SESSIONS = new HashMap();
private final Map<String, String> ID_TO_SESSION_KEY_MAPPING = new HashMap();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private TokenService tokenService;
public CustomSessionMappingStorage() {
}
@Override
public synchronized void addSessionById(String mappingId, HttpSession session) {
this.ID_TO_SESSION_KEY_MAPPING.put(session.getId(), mappingId);
this.MANAGED_SESSIONS.put(mappingId, session);
}
@Override
public synchronized void removeBySessionById(String sessionId) {
this.logger.debug("Attempting to remove Session=[{}]", sessionId);
String key = (String)this.ID_TO_SESSION_KEY_MAPPING.get(sessionId);
if (this.logger.isDebugEnabled()) {
if (key != null) {
this.logger.debug("Found mapping for session. Session Removed.");
} else {
this.logger.debug("No mapping for session found. Ignoring.");
}
}
this.MANAGED_SESSIONS.remove(key);
this.ID_TO_SESSION_KEY_MAPPING.remove(sessionId);
}
@Override
public synchronized HttpSession removeSessionByMappingId(String mappingId) {
StandardSessionFacade session = (StandardSessionFacade) this.MANAGED_SESSIONS.get(mappingId);
if (session != null) {
this.removeBySessionById(session.getId());
try {
String token = (String) session.getAttribute(Constants.CAS_TOKEN);
tokenService.delLoginUser(token);
} catch (IllegalStateException e) {
this.logger.error("已成功登出");
}
}
return session;
}
}
位置:
auth
模块的TokenController.java
文件中添加casLogin
方法
实现登录功能
/**
* 单点登录成功创建token
* @param request
* @param response
* @throws IOException
* @throws ServletException
**/
@GetMapping("casLogin")
public void casLogin(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String username = request.getRemoteUser();
HttpSession httpSession = request.getSession();
String url = request.getParameter("redirect");
LoginUser userInfo = sysLoginService.login(username);
Map<String, Object> token = tokenService.createToken(userInfo);
Cookie tokenCookie = new Cookie(Constants.WEB_TOKEN_KEY, (String) token.get("access_token"));
//必须设置path,否则获取不到cookie
tokenCookie.setPath("/");
response.addCookie(tokenCookie);
Cookie expiresCookie = new Cookie(Constants.WEB_TOKEN_EXPIRES, ((Long) token.get("expires_in")).toString());
expiresCookie.setPath("/");
response.addCookie(expiresCookie);
//设置后端认证成功标识
httpSession.setAttribute(Constants.CAS_TOKEN, token.get("access_token"));
//登录成功后跳转到前端访问页面
response.sendRedirect(url);
}
位置:在
auth
模块中添加CasConfig.java
文件
package com.ruoyi.auth.cas.config;
import com.ruoyi.auth.cas.config.properties.CasProperties;
import com.ruoyi.auth.cas.filter.NoCasFilter;
import com.ruoyi.auth.cas.storage.CustomSessionMappingStorage;
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class CasConfig {
@Autowired
private CasProperties casProperties;
@Autowired
private CustomSessionMappingStorage customSessionMappingStorage;
/**
* 单点登出过滤器
* @return
**/
@Bean
public FilterRegistrationBean logoutFilter() {
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean<>();
SingleSignOutFilter signOutFilter = new SingleSignOutFilter();
signOutFilter.setSessionMappingStorage(customSessionMappingStorage);
signOutFilter.setIgnoreInitConfiguration(true);
authenticationFilter.setFilter(signOutFilter);
authenticationFilter.addUrlPatterns("/*");
Map<String, String> initParameters = new HashMap<>();
initParameters.put("casServerUrlPrefix", casProperties.getCasServerUrlPrefix());
authenticationFilter.setInitParameters(initParameters);
authenticationFilter.setOrder(1);
if (casProperties.getEnabled()) {
return authenticationFilter;
}
return new FilterRegistrationBean<>(new NoCasFilter());
}
/**
* 单点登录认证入口
* @return
**/
@Bean
public FilterRegistrationBean authenticationFilterRegistrationBean() {
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(new AuthenticationFilter());
Map<String, String> initParameters = new HashMap<>();
initParameters.put("casServerLoginUrl", casProperties.getCasServerLoginUrl());
initParameters.put("serverName", casProperties.getServerName());
authenticationFilter.setInitParameters(initParameters);
authenticationFilter.setOrder(2);
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/casLogin");
authenticationFilter.setUrlPatterns(urlPatterns);
if (casProperties.getEnabled()) {
return authenticationFilter;
}
return new FilterRegistrationBean<>(new NoCasFilter());
}
/**
* 单点登录验证入口
* @return
**/
@Bean
public FilterRegistrationBean validationFilterRegistrationBean() {
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(new Cas20ProxyReceivingTicketValidationFilter());
Map<String, String> initParameters = new HashMap<>();
initParameters.put("casServerUrlPrefix", casProperties.getCasServerUrlPrefix());
initParameters.put("serverName", casProperties.getServerName());
initParameters.put("encoding", "UTF-8");
initParameters.put("useSession", "true");
authenticationFilter.setInitParameters(initParameters);
authenticationFilter.setOrder(3);
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/*");
authenticationFilter.setUrlPatterns(urlPatterns);
if (casProperties.getEnabled()) {
return authenticationFilter;
}
return new FilterRegistrationBean<>(new NoCasFilter());
}
/**
* 单点登录获取登录信息
* @return
**/
@Bean
public FilterRegistrationBean casHttpServletRequestWrapperFilter() {
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(new HttpServletRequestWrapperFilter());
authenticationFilter.setOrder(4);
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/*");
authenticationFilter.setUrlPatterns(urlPatterns);
if (casProperties.getEnabled()) {
return authenticationFilter;
}
return new FilterRegistrationBean<>(new NoCasFilter());
}
}
位置:
common-security
模块中的WebMvcConfig.java
,放行casLogin请求:
/** 不需要拦截地址 **/
public static final String[] excludeUrls = { "/casLogin", "/login", "/logout", "/refresh", "/register" };
修改
nacos
中ruoyi-gateway-dev.yml
,在网关中放行casLogin
请求:
# 不校验白名单
ignore:
whites:
- /auth/casLogin
- /auth/getToken
- /auth/logout
- /auth/login
- /auth/register
- /auth/updatePassword
- /*/v2/api-docs
- /csrf
至此,若依微服务后端集成CAS已完成。
powered by kaifamiao