一:在pom文件中引入security对cas支持的依赖
<!-- security对cas支持 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
二:在application.properties文件中引入cas服务端相关路径
cas:
server_host_url: http://www.casserver.com:8443
server_host_login_url: http://www.casserver.com:8443/login
server_host_logout_url: http://www.casserver.com:8443/logout?
service=http://localhost:8084/say
app_server_host_url: http://localhost:8084
app_login_url: /login
app_logout_url: /logout
三:定义CustomUserDetailsService类,
实现AuthenticationUserDetailsService
package com.jeeplus.security.service;
import com.jeeplus.core.errors.ErrorConstants;
import com.jeeplus.sys.constant.CommonConstants;
import com.jeeplus.sys.service.UserService;
import com.jeeplus.sys.service.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 用于加载用户信息
* @author: 王强
* @create: 2023-04-20 10:40
**/
public class CustomUserDetailsService implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
@Autowired
private UserService userService;
/**
* 当cas登录成功后会进入到这里
* @param token
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
System.out.println(token.getName());
return new User(token.getName(), "", AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
}
}
四:创建security配置类
package com.jeeplus.security.config;
import com.jeeplus.security.exception.JwtAccessDeniedHandler;
import com.jeeplus.security.exception.JwtAuthenticationEntryPoint;
import com.jeeplus.security.jwt.JWTConfigurer;
import com.jeeplus.security.jwt.TokenProvider;
import com.jeeplus.security.service.CustomUserDetailsService;
import com.jeeplus.security.util.DaoAuthenticationProvider;
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.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级安全验证
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// @Autowired
// private CustomUserDetailsService userDatailService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private JwtAccessDeniedHandler accessDeniedHandler;
@Autowired
private CasProperties casProperties;
/**
* 描述:设置授权处理相关的具体类以及加密方式
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(casAuthenticationProvider());
// DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
// // 设置不隐藏 未找到用户异常
// provider.setHideUserNotFoundExceptions(true);
// // 用户认证service - 查询数据库的逻辑
// provider.setUserDetailsService(userDetailsService());
// // 设置密码加密算法
// provider.setPasswordEncoder(passwordEncoder());
// provider.setUserDetailsService ( userDatailService );
// auth.authenticationProvider(provider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.authorizeRequests()//配置安全策略
// .antMatchers("/", "/hello").permitAll()//定义请求不需要验证
// .anyRequest().authenticated()//其余的所有请求都需要验证
// .and().logout().permitAll()//定义logout不需要验证
// .and().formLogin();//使用form表单登录
http
.headers().frameOptions().disable ().and ()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
// 由于使用的是JWT,我们这里不需要csrf
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 基于token,所以不需要session
// .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers ( "/401"
,"/404",
"/app/rest/**",
"/druid/**",
"/v1/**",
"/v2/**",
"/weboffice/**",
"/ReportServer/**",
"/sys/login",
"/app/sys/login",
"/sys/sysConfig/getConfig",
"/getAppFlowChart",
"/sys/getCode",
"/sys/getLoginCodeNumber",
"/cwProjectReport/signatureCallBack/**",
"/app/sys/getCode",
"/sys/casLogin",
"/hello",
"/app/luckyDraw/**",
"/sys/saveNewPassword",
"/sys/getPhoneCode").permitAll() // 允许请求无需认证
.antMatchers( HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated(); // 所有请求都需要验证
// .and ()
// .apply(securityConfigurerAdapter());
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
.and()
.addFilter(casAuthenticationFilter())
.addFilterBefore(casLogoutFilter(),LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
}
/**
* 描述: 静态资源放行,这里的放行,是不走 Spring Security 过滤器链
**/
@Override
public void configure(WebSecurity web) {
// 可以直接访问的静态数据
web.ignoring()
.antMatchers(
"/doc.html",
"/swagger-ui.html",
"/userfiles/**",
"/static/**",
"/swagger**/**",
"/webjars/**");
}
/**认证的入口*/
@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());
return casAuthenticationFilter;
}
/**cas 认证 Provider*/
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
//casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("casAuthenticationProviderKey");
return casAuthenticationProvider;
}
/**用户自定义的AuthenticationUserDetailsService*/
@Bean
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){
return new CustomUserDetailsService();
}
@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;
}
/**
* 描述: 密码加密算法 BCrypt 推荐使用
**/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 描述: 注入token
**/
@Bean
public TokenProvider tokenProvider() {
return new TokenProvider ();
}
private JWTConfigurer securityConfigurerAdapter() throws Exception{
return new JWTConfigurer(tokenProvider () , authenticationManager ());
}
/**
* 描述: 注入AuthenticationManager管理器
**/
@Override
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
建议根据项目对代码进行修改