0
点赞
收藏
分享

微信扫一扫

Cas整合Shiro

1.简介

CAS:Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法。

Shiro:Apache Shiro是一个Java安全框架,可以帮助我们完成认证、授权、会话管理、加密等,并且提供与web集成、缓存、rememberMed等功能。

Shiro支持与CAS进行整合使用.

2.整合步骤

2.1.新建工程

Cas整合Shiro_java

2.2.导入项目中需要的依赖

<?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>

<groupId>com.bruce.cas.shiro.demo</groupId>
<artifactId>CasShiro</artifactId>
<version>1.0-SNAPSHOT</version>

<!--导入SpringBoot的依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<shiro.version>1.2.4</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>

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

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>


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

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


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

<dependency>
<groupId>net.mingsoft</groupId>
<artifactId>shiro-freemarker-tags</artifactId>
<version>0.1</version>
</dependency>

<!--导入thymeleaf支持shiro的标签-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>

</dependencies>

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


</project>

2.3.启动类

package com.bruce;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @BelongsProject: CasShiro
* @BelongsPackage: com.bruce
* @Author: bruceliu
* @QQ:1241488705
* @CreateTime: 2020-04-10 23:08
* @Description: TODO
*/
@SpringBootApplication
public class App {

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

2.4.配置文件

server.port=8888

#Thymeleaf配置
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=utf-8
#设置为LEGACYHTML5编码格式
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

cas.casServerUrlPrefix=http://127.0.0.1:8080
cas.casServerLoginUrl=${cas.casServerUrlPrefix}/login
#cas.casServerLoginUrl=http://127.0.0.1:8081/shiroCAS/toLogin
cas.casServerLogoutUrl=${cas.casServerUrlPrefix}/logout?service=http://www.baidu.com
cas.casFilterUrlPattern=/shiro-cas
cas.localServerUrlPrefix=http://localhost:${server.port}
cas.localServerLoginUrl=${cas.casServerLoginUrl}?service=${cas.localServerUrlPrefix}${cas.casFilterUrlPattern}

2.5.加载CAS的配置文件

Cas整合Shiro_spring_02

package com.bruce.config;

/**
* @BelongsProject: CasShiro
* @BelongsPackage: com.bruce.config
* @Author: bruceliu
* @QQ:1241488705
* @CreateTime: 2020-04-17 22:45
* @Description: TODO
*/
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* 这个类是shiro整合cas的时候需要的一些配置
* 申明的一些变量
*/
@SpringBootConfiguration
@ConfigurationProperties(prefix = "cas")
public class CasConfig {

private String casServerUrlPrefix = "https://server.fable.com:8443/cas";
private String casServerLoginUrl = casServerUrlPrefix + "/login";
private String casServerLogoutUrl = casServerUrlPrefix + "/logout";
private String localServerUrlPrefix = "http://client1.fable.com:8081/aaaa";
private String casFilterUrlPattern = "/shiro-cas";
private String localServerLoginUrl = casServerLoginUrl + "?service=" + localServerUrlPrefix + casFilterUrlPattern;

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 getCasServerLogoutUrl() {
return casServerLogoutUrl;
}

public void setCasServerLogoutUrl(String casServerLogoutUrl) {
this.casServerLogoutUrl = casServerLogoutUrl;
}

public String getLocalServerUrlPrefix() {
return localServerUrlPrefix;
}

public void setLocalServerUrlPrefix(String localServerUrlPrefix) {
this.localServerUrlPrefix = localServerUrlPrefix;
}

public String getCasFilterUrlPattern() {
return casFilterUrlPattern;
}

public void setCasFilterUrlPattern(String casFilterUrlPattern) {
this.casFilterUrlPattern = casFilterUrlPattern;
}

public String getLocalServerLoginUrl() {
return localServerLoginUrl;
}

public void setLocalServerLoginUrl(String localServerLoginUrl) {
this.localServerLoginUrl = localServerLoginUrl;
}

public String getCasService() {
return localServerUrlPrefix + casFilterUrlPattern;
}
}

2.6.配置Realm

package com.bruce.shiro;

import com.bruce.pojo.User;
import com.bruce.service.IUserService;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.Set;


/**
* shiro和cas整合之后 继承CasRealm
*/
public class MyShiroCasRealm extends CasRealm{

@Autowired
private IUserService userService;

/**
* 权限认证(为当前登录的Subject授予角色和权限)
*
* 该方法的调用时机为需授权资源被访问时,并且每次访问需授权资源都会执行该方法中的逻辑,这表明本例中并未启用AuthorizationCache,
* 如果连续访问同一个URL(比如刷新),该方法不会被重复调用,Shiro有一个时间间隔(也就是cache时间,在ehcache-shiro.xml中配置),
* 超过这个时间间隔再刷新页面,该方法会被执行
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String loginName = (String) super.getAvailablePrincipal(principals);
User user = userService.findByUsername(loginName);
if (user != null){

// 权限信息对象info,用来存放查出的用户的所有的角色及权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//下面就是查询用户的权限
Set<String> roles=new HashSet<String>();
roles.add("admin");
roles.add("normal");
//下面也就可以查询用户的角色
Set<String> perms=new HashSet<String>();
perms.add("del");
perms.add("query");
perms.add("user:query");

info.setRoles(roles);
info.setStringPermissions(perms);

System.out.println("这里是授权的地方..............................");
return info;
}
// 返回null将会导致用户访问任何被拦截的请求时都会自动跳转到unauthorizedUrl指定的地址
return null;
}
}

2.7.配置ShiroFilterFactoryBean

package com.bruce.shiro;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.BeanInitializationException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
* 继承ShiroFilterFactoryBean处理拦截资源文件问题
*/
public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean {
// ShiroFilter将直接忽略的请求
private Set<String> ignoreExt;

public MyShiroFilterFactoryBean() {
super();
ignoreExt = new HashSet<String>();
ignoreExt.add(".jpg");
ignoreExt.add(".png");
ignoreExt.add(".gif");
ignoreExt.add(".bmp");
ignoreExt.add(".js");
ignoreExt.add(".css");
}

@Override
protected AbstractShiroFilter createInstance() throws Exception {
SecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
throw new BeanInitializationException("SecurityManager property must be set.");
}

if (!(securityManager instanceof WebSecurityManager)) {
throw new BeanInitializationException("The security manager does not implement the WebSecurityManager interface.");
}

PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
FilterChainManager chainManager = createFilterChainManager();
chainResolver.setFilterChainManager(chainManager);
return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}

private class MySpringShiroFilter extends AbstractShiroFilter {
public MySpringShiroFilter(
WebSecurityManager securityManager, PathMatchingFilterChainResolver chainResolver) {
super();
if (securityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
}
setSecurityManager(securityManager);
if (chainResolver != null) {
setFilterChainResolver(chainResolver);
}
}

@Override
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain chain)
throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String str = request.getRequestURI().toLowerCase();
boolean flag = true;
int idx = 0;
if ((idx = str.indexOf(".")) > 0) {
str = str.substring(idx);
if (ignoreExt.contains(str.toLowerCase())) {
flag = false;
}
}
if (flag) {
super.doFilterInternal(servletRequest, servletResponse, chain);
} else {
chain.doFilter(servletRequest, servletResponse);
}
}
}
}

2.8. Shiro集成CAS配置

package com.bruce.shiro;

import com.bruce.config.CasConfig;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.cas.CasFilter;
import org.apache.shiro.cas.CasSubjectFactory;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* Shiro集成CAS配置
*/
@Configuration
@EnableConfigurationProperties(CasConfig.class)
public class ShiroCasConfiguration {

private static final String CAS_FILTER = "casFilter";

@Bean
public EhCacheManager ehcacheManager(){
EhCacheManager ehcacheManager = new EhCacheManager();
ehcacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return ehcacheManager;
}

@Bean(name = "myShiroCasRealm")
public MyShiroCasRealm myShiroRealm(EhCacheManager ehCacheManager, CasConfig casConfig){
MyShiroCasRealm realm = new MyShiroCasRealm();
realm.setCacheManager(ehCacheManager);
realm.setCasServerUrlPrefix(casConfig.getCasServerUrlPrefix());
realm.setCasService(casConfig.getCasService());
return realm;
}

/**
* 注册shiroFilter
*/
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
// 该值缺省为false,表示生命周期有SpringApplicationContext管理,设置为true则表示由ServletContainer管理
filterRegistration.addInitParameter("targetFilterLifecycle", "true");
filterRegistration.setEnabled(true);
filterRegistration.addUrlPatterns("/*");
return filterRegistration;
}

@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}

@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}

@Bean(name = "securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(MyShiroCasRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
securityManager.setCacheManager(ehcacheManager());
// 指定SubjectFactory
securityManager.setSubjectFactory(new CasSubjectFactory());
return securityManager;
}

@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}

@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager, CasConfig casConfig, CasFilter casFilter){
ShiroFilterFactoryBean factoryBean = new MyShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
factoryBean.setLoginUrl(casConfig.getLocalServerLoginUrl());
factoryBean.setSuccessUrl("/user");
factoryBean.setUnauthorizedUrl("/403");
// 添加casFilter到shiroFilter中
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
filterMap.put(CAS_FILTER, casFilter);
factoryBean.setFilters(filterMap);
loadShiroFilterChain(factoryBean, casConfig);
return factoryBean;
}

/**
* 加载ShiroFilter权限控制规则
*/
private void loadShiroFilterChain(ShiroFilterFactoryBean factoryBean, CasConfig casConfig) {
/**下面这些规则配置最好配置到配置文件中*/
Map<String, String> filterChainMap = new LinkedHashMap<String, String>();
filterChainMap.put(casConfig.getCasFilterUrlPattern(), CAS_FILTER);//shiro集成cas后,首先添加该规则
filterChainMap.put("/main", "anon");
filterChainMap.put("/**", "authc");
factoryBean.setFilterChainDefinitionMap(filterChainMap);
}

/**
* CAS过滤器
*/
@Bean
public CasFilter casFilter(CasConfig casConfig){
CasFilter casFilter = new CasFilter();
casFilter.setName(CAS_FILTER);
casFilter.setEnabled(true);
casFilter.setFailureUrl(casConfig.getLocalServerLoginUrl());
return casFilter;
}

}

2.9.集成Shiro标签

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

/**
* 集成Shiro标签
*/
@SpringBootConfiguration
public class ShiroTagThymeleafConfigurer{
/**
* 配置的是方言
* @return
*/
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}

2.10.页面使用

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<h1>用户列表-<a href="logout">登出</a></h1>
<h2>权限列表</h2>
<shiro:authenticated>用户已经登录显示此内容</shiro:authenticated><br/>
<shiro:hasRole name="manager">manager角色登录显示此内容</shiro:hasRole><br/>
<shiro:hasRole name="admin">admin角色登录显示此内容</shiro:hasRole><br/>
<shiro:hasRole name="normal">normal角色登录显示此内容</shiro:hasRole><br/>
<shiro:hasAnyRoles name="manager,admin">manager或admin角色用户登录显示此内容</shiro:hasAnyRoles><br/>
<shiro:principal>-显示当前登录用户名-</shiro:principal><br/>
<shiro:hasPermission name="add">add权限用户显示此内容</shiro:hasPermission><br/>
<br/>所有用户列表:<br/>

<ul th:each="user1,iterStat: ${userList}">
<li th:text="${user1.userName}"></li>
</ul>

</body>
</html>


举报

相关推荐

0 条评论