CAS单点登录:CAS客户端搭建(整合Shiro和Spring Boot)

上一篇我们试着搭建了一个简单的CAS服务端,在这一篇中,我们将整合Shiro搭建一个CAS客户端。

1 新建Maven项目,引入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>gdou.laixiaoming</groupId>
	<artifactId>cas-client-a</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>cas-client-a</name>
	<description>CAS Client Demo.</description>

	<properties>
		<java.version>1.8</java.version>
		<shiro.version>1.4.0</shiro.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- shiro -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-cas</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-aspectj</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2 Shiro配置

扩展CasRealm,在登录成功后,可以获取到登录的用户名,在客户端这边再把用户拥有的角色和权限查询出来并保存:

public class MyCasRealm extends CasRealm{

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取用户名
        String username = (String)principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//        authorizationInfo.setRoles(new HashSet<>(Arrays.asList("admin")));
//        authorizationInfo.setStringPermissions(new HashSet<>(Arrays.asList("admin")));

        return authorizationInfo;
    }
}

Shiro配置:

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //配置自定义casFilter
        Map<String, Filter> filters = new LinkedHashMap<>();
        CasFilter casFilter = new CasFilter();
        casFilter.setFailureUrl("/casFailure");
        filters.put("cas", casFilter);
        shiroFilterFactoryBean.setFilters(filters);

        //配置filter调用链
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        //anon为匿名,不拦截
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/casFailure", "anon");
        //拦截CAS Server返回的ticket
        filterChainDefinitionMap.put("/cas", "cas");
        //退出登录
        filterChainDefinitionMap.put("/logout", "anon");
        filterChainDefinitionMap.put("/logouttips", "anon");
        //需要登录访问的页面
        filterChainDefinitionMap.put("/**", "user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        //service指定了登录成功后的回调地址,回调/cas将被CasFilter拦截,获取服务端返回的Service Ticket进行登录
        shiroFilterFactoryBean.setLoginUrl("https://www.laixiaoming.com:8443/cas/login?service=http://www.localhost1.com:9090/cas");
        //登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/");
        //未授权跳转页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        return shiroFilterFactoryBean;
    }


    @Bean
    public MyCasRealm casRealm(){
        //使用自定义Realm
        MyCasRealm casRealm = new MyCasRealm();
        casRealm.setCachingEnabled(true);
        casRealm.setAuthenticationCachingEnabled(true);
        casRealm.setAuthenticationCacheName("authenticationCache");
        casRealm.setAuthorizationCachingEnabled(true);
        casRealm.setAuthorizationCacheName("authorizationCache");
        //指定CAS服务端地址
        casRealm.setCasServerUrlPrefix("https://www.laixiaoming.com:8443/cas");
        //当前应用的CAS服务URL,用于接收和处理CAS服务端的Ticket
        casRealm.setCasService("http://www.localhost1.com:9090/cas");
        return casRealm;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(casRealm());
        return securityManager;
    }

    /**
     * Shiro生命周期处理器
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启Shiro AOP的注解支持(如@RequiresRoles,@RequiresPermissions)
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}

3 单点登出配置

退出登录时,将页面重定向到CAS的退出页面,service参数的设置指定了退出登录后的回调地址:

@GetMapping("/logout")
	public String logout(){
		SecurityUtils.getSubject().logout();
		return "redirect:https://www.laixiaoming.com:8443/cas/logout?service=https://www.laixiaoming.com:9090/logouttips";
	}

service参数名可以在CAS服务端通过修改application.properties进行配置,关于登出的更多配置,可见官网

#单点登出
#配置允许登出后跳转到指定页面
cas.logout.followServiceRedirects=true
#跳转到指定页面需要的参数名为 service
cas.logout.redirectParameter=service

在CAS服务端退出后,会向注册的每个服务发送登出请求,该请求可以由SingleSignOutFilter进行拦截并销毁当前会话:

@Configuration
public class CasConfig {

    @Bean
    public FilterRegistrationBean singleSignOutFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new SingleSignOutFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }

    @Bean
    public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutListenerRegistration() {
        ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> registration =
                new ServletListenerRegistrationBean<>(new SingleSignOutHttpSessionListener());
        return registration;
    }
}

4 CAS服务端配置

客户端搭建好后,需要在CAS服务端上配置哪些服务可以注册到CAS服务端上,服务的管理也有许多方式,这里使用的JSON的方式,需要先在服务端引入相关依赖(更多说明见官网):

<dependency>
			<groupId>org.apereo.cas</groupId>
			<artifactId>cas-server-support-json-service-registry</artifactId>
			<version>${cas.version}</version>
		</dependency>

然后,在已经生成的war包中找到文件:
在这里插入图片描述
将文件复制到这个位置:
在这里插入图片描述
修改,serviceId指定允许注册的客户端,更多配置见官网

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://(www\\.localhost1\\.com:9090|www\\.localhost2\\.com:9091)/.*",
  "name" : "HTTPS and IMAPS",
  "id" : 10000001,
  "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",
  "evaluationOrder" : 10000
}

同时在application.properties指定配置文件位置:

#客户端服务注册
cas.serviceRegistry.json.location=classpath:/services

至此,CAS客户端搭建完成了,完整代码见:GitHub
参考:
https://blog.csdn.net/qq_34021712/article/category/8004639/1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值