学习笔记:微服务-6.spring zuul + spring security + cas client 实现微服务sso登录

上节架构了spring zuul实现微服务的网页路由,因为zuul是微服务群的统一入口,非常适合在zuul服务上进行统一登录认证,本节实验结合spring zuul +spring security +Apereo cas实现微服务群的统一登录认证

spring security是一个spring的权限认证系统,cas是单位中央认证系统,从中央认证系统认证后,获取一个中央认证系统的身份(本测试中认证用户名linbin),spring security对这个用户名进行映射,比如这里映射为spring security的登录用户admin(可以通过数据库查询映射关系),并设置admin用户的权限,从而实现统一登录认证到本spring boot微服务的本地系统用户和权限的转换,而因zuul的统一api入口地位,这个登录可以作为整个微服务群的统一登录

1. 新建spring boot 微服务项目 Eureka-Client-zuul

pom.xml  全文



	4.0.0
	
		org.springframework.boot
		spring-boot-starter-parent
		2.1.1.RELEASE
		 
	
	com.linbin
	Eureda-Client-zuul
	0.0.1-SNAPSHOT
	Eureda-Client-zuul
	Demo project for Spring Boot
	
		UTF-8
		UTF-8
		1.8
		Greenwich.M3
	
	
		
			org.springframework.boot
			spring-boot-starter-web
		
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-zuul
        
       
        org.springframework.cloud
        spring-cloud-starter-config
       
      
        org.springframework.boot
		  spring-boot-starter-security 
		  
   
       org.springframework.security
       spring-security-cas
    

		
			org.springframework.boot
			spring-boot-starter-test
			test
		
	
	
		
			
				org.springframework.cloud
				spring-cloud-dependencies
				${spring-cloud.version}
				pom
				import
			
		
	
		
		
			spring-milestones
			Spring Milestones
			https://repo.spring.io/milestone
			
				false
			
		
	
	
		
			
				org.springframework.boot
				spring-boot-maven-plugin
			
		
	

关键依赖:

     
        org.springframework.boot
          spring-boot-starter-security 
        
 
   
       org.springframework.security
       spring-security-cas
   

2.  application.properties 配置

server.port=8000
eureka.client.serviceUrl.defaultZone=http://admin:123@centos7:8888/eureka/
spring.application.name=Euredaclientzuul
zuul.routes.euredaclient1.path=/c1/**
zuul.routes.euredaclient1.serviceId=Euredaclient1
zuul.routes.springdemo.path=/sd/**
zuul.routes.springdemo.serviceId=SpringDemo
spring.session.store-type=none

3. java文件目录

学习笔记:微服务-6.spring zuul + spring security + cas client 实现微服务sso登录_第1张图片

4. 启动类EuredaClientZuulApplication 

@EnableZuulProxy
@SpringBootApplication
public class EuredaClientZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(EuredaClientZuulApplication.class, args);
    }

}
5.WebSecurityConfig 类 是 spring security 配置实例

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	 @Autowired 
	 private AuthenticationEntryPoint authenticationEntryPoint; 
	 @Autowired 
	 private AuthenticationProvider authenticationProvider; 
	 @Autowired 
	 private SingleSignOutFilter singleSignOutFilter; 
	 @Autowired 
	 private LogoutFilter logoutFilter; 
	 @Override 
	 protected void configure(HttpSecurity http) throws Exception { 
		 //所有都需要认证才能访问 //由于设置了验证filter访问为,/login/cas,所以必须通过验证,否则出现死循环 
		 http
		 .authorizeRequests()
		 .antMatchers("/login/cas")
		 .permitAll()
		 .and()
		 .authorizeRequests()
		 .anyRequest()
		 .authenticated()
		 .and()
		 .httpBasic()
		 .authenticationEntryPoint(authenticationEntryPoint)
		 .and()
		 .logout()
		 .logoutSuccessUrl("/logout")
		 .and()
		 .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class)
		 .addFilterBefore(logoutFilter, LogoutFilter.class);
		 } 
	 @Override 
	 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
		 auth.authenticationProvider(authenticationProvider); 
		 } 
	 @Override 
	 protected AuthenticationManager authenticationManager() throws Exception { 
		 //设置cas认证提供 
		 return new ProviderManager( Arrays.asList(authenticationProvider)); 
		 } 
	 @Bean 
	 public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties sp) throws Exception { 
		 //cas认证过滤器,当触发本filter时,对ticket进行认证 
		 CasAuthenticationFilter filter = new CasAuthenticationFilter(); 
		 filter.setServiceProperties(sp); 
		 filter.setAuthenticationManager(authenticationManager()); return filter; } 
	 @Override public void configure(WebSecurity web) throws Exception { super.configure(web); 
	 }
}

6.  CasSecurityConfig 实现与cas的接口配置

@Configuration
public class CasSecurityConfig {
	//cas服务 
	@Value("${cas.server.url:https://author.linbsoft.com/cas}") 
	private String casServerUrl; 
	@Bean 
	public ServiceProperties serviceProperties() { 
		ServiceProperties serviceProperties = new ServiceProperties(); 
		//本机服务,访问/login/cas时进行校验登录 
		serviceProperties.setService("http://springcloud.linbsoft.com:8000/login/cas"); 
		serviceProperties.setSendRenew(false); 
		return serviceProperties; 
		} 
	
	@Bean 
	@Primary 
	public AuthenticationEntryPoint authenticationEntryPoint( ServiceProperties sP) { 
		CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint(); 
		//cas登录服务 
		entryPoint.setLoginUrl(casServerUrl + "/login"); 
		entryPoint.setServiceProperties(sP); 
		return entryPoint; 
		} 
	@Bean 
	public TicketValidator ticketValidator() { 
		//指定cas校验器 
		return new Cas30ServiceTicketValidator( casServerUrl); 
		} 
	//cas认证 
	@Bean 
	public CasAuthenticationProvider casAuthenticationProvider() { 
		CasAuthenticationProvider provider = new CasAuthenticationProvider(); 
		provider.setServiceProperties(serviceProperties()); 
		provider.setTicketValidator(ticketValidator()); 
		provider.setUserDetailsService(customUserDetailsService()); 
		provider.setKey("CAS_PROVIDER_LOCALHOST_8000"); 
		return provider; 
		} 
	@Bean 
    public UserDetailsService customUserDetailsService(){ 
        return new CustomUserDetailsService(); 
    }
	@Bean 
	public SecurityContextLogoutHandler securityContextLogoutHandler() { 
		return new SecurityContextLogoutHandler(); 
		} 
	@Bean 
	public LogoutFilter logoutFilter() { 
		//退出后转发路径 
		LogoutFilter logoutFilter = new LogoutFilter( casServerUrl + "/logout", securityContextLogoutHandler()); 
		//cas退出 
		logoutFilter.setFilterProcessesUrl("/logout/cas"); 
		return logoutFilter; 
		} 
	@Bean 
	public SingleSignOutFilter singleSignOutFilter() { 
		//单点退出 
		SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter(); 
		singleSignOutFilter.setCasServerUrlPrefix(casServerUrl); 
		singleSignOutFilter.setIgnoreInitConfiguration(true); 
		return singleSignOutFilter; 
		} 
	//设置退出监听 
	@EventListener 
	public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener( HttpSessionEvent event) { 
		return new SingleSignOutHttpSessionListener(); 
		}
	
	}

7. CustomUserDetailsService 实现UserDetailsService接口

public class CustomUserDetailsService     implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("当前的用户名是:"+username);
        //这里为了方便测试,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setId(104566569938L);
        userInfo.setUsername("admin");
        userInfo.setName("admin");
        Set authorities = new HashSet();
        AuthorityInfo authorityInfo = new AuthorityInfo("TEST-Roll");
        authorities.add(authorityInfo);
        authorityInfo = new AuthorityInfo("write-table-roll");
        authorities.add(authorityInfo);    
        userInfo.setAuthorities(authorities);
        return userInfo;
    }

}

8.   UserInfo  保存登录用户信息的类,CustomUserDetailsService 需要调用

public class UserInfo implements UserDetails {
	private static final long serialVersionUID = -1041327031937199938L;
	private Long id;
	private String name;
 	private String username;
	private String password;
	private boolean isAccountNonExpired = true;
	private boolean isAccountNonLocked = true;
	private boolean isCredentialsNonExpired = true;
	private boolean isEnabled = true;
	private Set authorities = new HashSet();
	@Override
	public Collection getAuthorities() {
		return	authorities;
	}

	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return username;
	}

	@Override
	public boolean isAccountNonExpired() {
		return this.isAccountNonExpired;
	}

	@Override
	public boolean isAccountNonLocked() {
		return this.isAccountNonLocked;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return this.isCredentialsNonExpired;
	}

	@Override
	public boolean isEnabled() {
		return this.isEnabled;
	}

	public void setUsername(String string) {
		this.username=string;
  }

	public void setName(String string) {
		this.name=string;
		
	}
	public String getName() {
		return this.name;
		
	}

	public void setAuthorities(Set authorities2) {
		authorities=authorities2;
	}
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setAccountNonExpired(boolean isAccountNonExpired) {
		this.isAccountNonExpired = isAccountNonExpired;
	}

9. AuthorityInfo 是保存权限信息的类,UserInfo类需要使用

public class AuthorityInfo  implements GrantedAuthority{
    private static final long serialVersionUID = -175781100474818800L;
    /**
     * 权限CODE
     */
    private String authority;
    public AuthorityInfo(String authority) {
        this.authority = authority;
    }
    @Override
    public String getAuthority() {
        return authority;
    }
    public void setAuthority(String authority) {
        this.authority = authority;
    }

}
 

10.  创建一个showuser类用来测试显示登录认证后的本地用户及权限

@RestController
public class showuser {
    @RequestMapping("/user")
    public String showloginuser() {
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext() 
                .getAuthentication() 
                .getPrincipal(); 
        String user= "登陆用户:"+ userDetails.getUsername() +"
登陆权限:";
        for (GrantedAuthority grantedAuthority : userDetails.getAuthorities()) {
            user += ("
Authority:" + grantedAuthority.getAuthority());
        }
        return user;
    }
}

11. 全部类及配置介绍完毕,启动Eureda server微服务,再启动本例 Eureka-Client-zuul 服务

浏览器 http://springcloud.linbsoft.com:8000  本案例地址

会自动条转到 cas登录界面,登录后在eclipse控制台可以看见cas登录用户

学习笔记:微服务-6.spring zuul + spring security + cas client 实现微服务sso登录_第2张图片

控制台显示的是cas中央认证系统的登录用户

12. 在浏览器跳转到本地再进入 http://springcloud.linbsoft.com:8000/user 可以看见映射的本地账号

学习笔记:微服务-6.spring zuul + spring security + cas client 实现微服务sso登录_第3张图片

到此,实现了登录外部中央认证系统到登录本地应用的spring secutiry认证系统的流程

参考了多位网友的文章,在这一致致谢!

 

 

你可能感兴趣的:(系统集成,java,spring,cloud)