Springboot+Security+Cas整合

共 11045字,需浏览 23分钟

 ·

2020-10-20 13:42

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

66套java从入门到精通实战课程分享

我的整合是基于Springboot 2.0版本  +  Cas 5.X版本

获取的用户信息,需要自己在Cas的服务端进行设置用户信息的返回内容

CAS默认只回显用户名 

一、pom.xml文件,加入以下内容



    org.jasig.cas.client
    cas-client-core
    3.5.0



    org.springframework.security
    spring-security-cas



    org.springframework.security
    spring-security-taglibs

二、application.properties文件,加入以下内容

#CAS服务地址 
security.cas.server.host.url=http://XXXXX/cas 
#CAS服务登录地址 
security.cas.server.host.login_url=${security.cas.server.host.url}/login 
#CAS服务登出地址 
security.cas.server.host.logout_url=${security.cas.server.host.url}/logout?service=${security.app.server.host.url}
#应用访问地址 
security.app.server.host.url=http://localhost:8080
#应用登录地址
security.app.login.url=/user/login
#应用登出地址 
security.app.logout.url=/logout 

三、security配置文件SecurityConfig,项目启动的时候执行,初始化security和cas的设置

import org.XXX.service.CustomUserDetailsService;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
 
 
/**
 * Security的配置
 */ 
@Configuration
@EnableWebSecurity //启用web权限
@EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 @Autowired
 private CasProperties casProperties;
 
 /**定义认证用户信息获取来源,密码校验规则等*/
 @Override
 protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  super.configure(auth);
  auth.authenticationProvider(casAuthenticationProvider());
 }
 
 /**定义安全策略*/
 @Override
 protected void configure(HttpSecurity http) throws Exception {
                http.csrf().and()
                .headers()
                .frameOptions().sameOrigin()
                .xssProtection()
                .block(true)
                .and();
 
  http
                .headers()
                .cacheControl()
                .and()
                .contentTypeOptions()
                .and()
                .httpStrictTransportSecurity()
                .and()
                .xssProtection();
 
  http.authorizeRequests()//配置安全策略
   .antMatchers("/","/home/**","/seach/**","/user/**").permitAll()//定义/请求不需要验证
   .antMatchers("/login/**").authenticated()//login下请求需要验证
   .and()
  .logout()
   .permitAll()//定义logout不需要验证
   .and()
  .formLogin();//使用form表单登录
  
  http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
   .and()
   .addFilter(casAuthenticationFilter())
   .addFilterBefore(casLogoutFilter(), LogoutFilter.class)
   .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
  
  //http.csrf().disable(); //禁用CSRF
                http.csrf().ignoringAntMatchers("/api/**");
  
 }
 
 /**指定service相关信息*/
 @Bean
 public ServiceProperties serviceProperties() {
  ServiceProperties serviceProperties = new ServiceProperties();
  serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
  serviceProperties.setAuthenticateAllArtifacts(true);
  return serviceProperties;
 }
 
 /**认证的入口*/
 @Bean
 public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
  CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
  casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
  casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
  return casAuthenticationEntryPoint;
 }
 
 /**CAS认证过滤器*/
 @Bean
 public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
  CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
  casAuthenticationFilter.setAuthenticationManager(authenticationManager());
  casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
  return casAuthenticationFilter;
 }
 
 @Bean
 public Cas30ServiceTicketValidator cas30ServiceTicketValidator() {
  return new Cas30ServiceTicketValidator(casProperties.getCasServerUrl());
 }
 
 /**cas 认证 Provider*/
 @Bean
 public CasAuthenticationProvider casAuthenticationProvider() {
  CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
  casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
  //casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。
  casAuthenticationProvider.setServiceProperties(serviceProperties());
  casAuthenticationProvider.setTicketValidator(cas30ServiceTicketValidator());
  casAuthenticationProvider.setKey("casAuthenticationProviderKey");
  return casAuthenticationProvider;
 }
 
 /**用户自定义的AuthenticationUserDetailsService*/
 @Bean
 public AuthenticationUserDetailsService customUserDetailsService(){
  return new CustomUserDetailsService();
 }
 
 /**单点登出过滤器*/
 @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;
 }
}

这里service里设置的路径是 http://localhost:8080/user/login ,保证这个路径能正常返回,登陆成功后才能正常返回ticket,执行后面的CustomUserDetailsService类中的loadUserDetails方法。 

四、CasProperties类,用于将properties文件指定的内容注入以方便使用

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
/**
 * CAS的配置参数
 */
@Component
public class CasProperties {
 
        @Value("${security.cas.server.host.url}")
        private String casServerUrl;
 
        @Value("${security.cas.server.host.login_url}")
        private String casServerLoginUrl;
 
        @Value("${security.cas.server.host.logout_url}")
        private String casServerLogoutUrl;
 
        @Value("${security.app.server.host.url}")
        private String appServerUrl;
 
        @Value("${security.app.login.url}")
        private String appLoginUrl;
 
        @Value("${security.app.logout.url}")
        private String appLogoutUrl;
 
 public String getCasServerUrl() {
  return casServerUrl;
 }
 
 public void setCasServerUrl(String casServerUrl) {
  this.casServerUrl = casServerUrl;
 }
 
 public String getCasServerLoginUrl() {
  return casServerLoginUrl;
 }
 
 public void setCasServerLoginUrl(String casServerLoginUrl) {
  this.casServerLoginUrl = casServerLoginUrl;
 }
 
 public String getCasServerLogoutUrl() {
  return casServerLogoutUrl;
 }
 
 public void setCasServerLogoutUrl(String casServerLogoutUrl) {
  this.casServerLogoutUrl = casServerLogoutUrl;
 }
 
 public String getAppServerUrl() {
  return appServerUrl;
 }
 
 public void setAppServerUrl(String appServerUrl) {
  this.appServerUrl = appServerUrl;
 }
 
 public String getAppLoginUrl() {
  return appLoginUrl;
 }
 
 public void setAppLoginUrl(String appLoginUrl) {
  this.appLoginUrl = appLoginUrl;
 }
 
 public String getAppLogoutUrl() {
  return appLogoutUrl;
 }
 
 public void setAppLogoutUrl(String appLogoutUrl) {
  this.appLogoutUrl = appLogoutUrl;
 }
 
}

五、定义CustomUserDetailsService类

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
 
import org.XXX.entity.AuthorityInfo;
import org.XXX.entity.UserInfo;
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;
 
/**
 * 用于加载用户信息 实现UserDetailsService接口,或者实现AuthenticationUserDetailsService接口
 */
@Service
public class CustomUserDetailsService implements AuthenticationUserDetailsService {           
    @Override
    public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
                // 结合具体的逻辑去实现用户认证,并返回继承UserDetails的用户对象;
  System.out.println("当前的用户名是:"+token.getName());
  
  //获取用户信息
  UserInfo userInfo = new UserInfo();
  userInfo.setUsername(token.getName());
  userInfo.setRole("ROLE_USER");
  Map userAttributess = token.getAssertion().getPrincipal().getAttributes();
  //System.out.println(userAttributess.toString());
  if (userAttributess != null) {
   userInfo.setId( String.valueOf(userAttributess.get("id")));
   userInfo.setNickname( String.valueOf(userAttributess.get("nickname")));
   userInfo.setRealName( String.valueOf(userAttributess.get("real_name")));
   userInfo.setEmail( String.valueOf(userAttributess.get("email")));
   userInfo.setCountryCode( String.valueOf(userAttributess.get("country_code")));
  }
  
  System.out.println(userInfo.toString());
                return userInfo;
    }
 
}

六、定义UserInfo类,用于加载当前用户信息,实现UserDetails接口

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
 
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
 
/**
 * 用户信息
 */
public class UserInfo extends User implements UserDetails {
 private static final long serialVersionUID = -1041327031937199938L;
 
        private String id;
        private String username;
        private String email;
        private String countryCode;
        private String mobile;
        private String nickname;
        private String role;
        private String realName;
    
        private String password;
    
 private boolean isAccountNonExpired = true; //是否过期
 
 private boolean isAccountNonLocked = true;//账户未锁定为true
 
 private boolean isCredentialsNonExpired = true;//证书不过期为true
 
 private boolean isEnabled = true;//是否可用
 
        @Override
        public Collection getAuthorities() {
            if(this.getRole() == null || this.getRole().length() <1){
                return AuthorityUtils.commaSeparatedStringToAuthorityList("");
            }
            else{
                return AuthorityUtils.commaSeparatedStringToAuthorityList(this.getRole());
            }
        }
 
 
 public String getId() {
  return id;
 }
 
 
 public void setId(String id) {
  this.id = id;
 }
 
 
 public String getUsername() {
  return username;
 }
 
 
 public void setUsername(String username) {
  this.username = username;
 }
 
 
 public String getEmail() {
  return email;
 }
 
 
 public void setEmail(String email) {
  this.email = email;
 }
 
 
 public String getCountryCode() {
  return countryCode;
 }
 
 
 public void setCountryCode(String countryCode) {
  this.countryCode = countryCode;
 }
 
 
 public String getMobile() {
  return mobile;
 }
 
 
 public void setMobile(String mobile) {
  this.mobile = mobile;
 }
 
 
 public String getNickname() {
  return nickname;
 }
 
 
 public void setNickname(String nickname) {
  this.nickname = nickname;
 }
 
 
 public String getRole() {
  return role;
 }
 
 
 public void setRole(String role) {
  this.role = role;
 }
 
 
 public String getRealName() {
  return realName;
 }
 
 
 public void setRealName(String realName) {
  this.realName = realName;
 }
 
 
 public String getPassword() {
  return password;
 }
 
 
 public void setPassword(String password) {
  this.password = password;
 }
 
 
 public boolean isAccountNonExpired() {
  return isAccountNonExpired;
 }
 
 
 public void setAccountNonExpired(boolean isAccountNonExpired) {
  this.isAccountNonExpired = isAccountNonExpired;
 }
 
 
 public boolean isAccountNonLocked() {
  return isAccountNonLocked;
 }
 
 
 public void setAccountNonLocked(boolean isAccountNonLocked) {
  this.isAccountNonLocked = isAccountNonLocked;
 }
 
 
 public boolean isCredentialsNonExpired() {
  return isCredentialsNonExpired;
 }
 
 
 public void setCredentialsNonExpired(boolean isCredentialsNonExpired) {
  this.isCredentialsNonExpired = isCredentialsNonExpired;
 }
 
 
 public boolean isEnabled() {
  return isEnabled;
 }
 
 
 public void setEnabled(boolean isEnabled) {
  this.isEnabled = isEnabled;
 }
 
 
 @Override
 public String toString() {
  return "UserInfo [id=" + id + ", username=" + username + ", email=" + email + ", countryCode=" + countryCode
    + ", mobile=" + mobile + ", nickname=" + nickname + ", role=" + role + ", realName=" + realName
    + ", password=" + password + ", isAccountNonExpired=" + isAccountNonExpired + ", isAccountNonLocked="
    + isAccountNonLocked + ", isCredentialsNonExpired=" + isCredentialsNonExpired + ", isEnabled="
    + isEnabled + "]";
 }
 
}

七、启动服务端,登陆之后,回显数据

UserInfo [
 id=XXXX, 
 username=XXXX, 
 email=XXXXX@163.com, 
 countryCode=null, 
 mobile=null, 
 nickname=null, 
 role=ROLE_USER, 
 realName=null, 
 password=null, 
 isAccountNonExpired=true
 isAccountNonLocked=true
 isCredentialsNonExpired=true
 isEnabled=true
]


八、常见错误(无限重定向 和 401错误)

https://blog.csdn.net/mushuntaosama/article/details/72763864






版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:

https://blog.csdn.net/w_meng_h/article/details/86673630






粉丝福利:108本java从入门到大神精选电子书领取

???

?长按上方锋哥微信二维码 2 秒
备注「1234」即可获取资料以及
可以进入java1234官方微信群



感谢点赞支持下哈 

浏览 40
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报