springboot 整合shiro + cas 实现单点登录权限管理(一)(sso)
2019-07-21 23:25
761 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_27221711/article/details/96776851
简介
- 本项目将单点登录和权限认证结合在一起,实现了用户登录与授权的基础框架,后续可以很好的在此框架上进行二次开发
- 在原理和配置上也有很多不清楚的地方,希望大家留言讨论~
- 后续将会进行spring cloud系列工程的搭建,并将shiro-cas尝试接入spring cloud中
- spring cloud系列直达地址 spring cloud
- 项目源码见最底部
准备:cas服务器搭建
单点登录流程
- 客户端请求目标服务器
- 目标服务器重定向到cas服务器
- cas服务器进行验证,通过则请求目标服务器,将ticket传给目标服务器
- 目标服务器根据ticket,请求cas服务器,获取用户登录信息
- cas服务器返回验证消息给目标服务器
项目实现
1、导入依赖包
<!--Apache Shiro --> <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>
2、 编辑配置文件
- 以下为shiro-cas相关部分
# shiro - cas 配置 shiro: # 在访问cas服务器登录之后,会返回一个ticket。由该地址接收 casFilterUrlPattern: /shiro-cas # cas服务前缀 casServerUrlPrefix: http://127.0.0.1:8181/cas # shiro服务前缀 shiroServerUrlPrefix: http://127.0.0.1:${server.port}${server.servlet.context-path} # 登录地址 loginUrl: ${shiro.casServerUrlPrefix}/login?service=${shiro.shiroServerUrlPrefix}${shiro.casFilterUrlPattern} # 登出地址 logoutUrl: ${shiro.casServerUrlPrefix}/logout?service=${shiro.shiroServerUrlPrefix}${shiro.casFilterUrlPattern}
- 以下为全量配置
# Tomcat server: tomcat: uri-encoding: UTF-8 max-threads: 1000 min-spare-threads: 30 port: 40301 connection-timeout: 5000ms servlet: context-path: /shiro session: cookie: http-only: true spring: application: name: service-auth # shiro - cas 配置 shiro: # 在访问cas服务器登录之后,会返回一个ticket。由该地址接收 casFilterUrlPattern: /shiro-cas # cas服务前缀 casServerUrlPrefix: http://127.0.0.1:8181/cas # shiro服务前缀 shiroServerUrlPrefix: http://127.0.0.1:${server.port}${server.servlet.context-path} # 登录地址 loginUrl: ${shiro.casServerUrlPrefix}/login?service=${shiro.shiroServerUrlPrefix}${shiro.casFilterUrlPattern} # 登出地址 logoutUrl: ${shiro.casServerUrlPrefix}/logout?service=${shiro.shiroServerUrlPrefix}${shiro.casFilterUrlPattern}
3、自定义配置casFileter
import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.cas.CasFilter; import org.apache.shiro.cas.CasToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; /** * @author : xingsongtan@qq.com * @date : 14:17 2019/7/17 */ public class MyCasFilter extends CasFilter { private static Logger logger = LoggerFactory.getLogger(MyCasFilter.class); private static final String TICKET_PARAMETER = "ticket"; public MyCasFilter() { } @Override public AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception { // 获取请求的ticket HttpServletRequest httpRequest = (HttpServletRequest) request; String ticket = getRequestTicket(httpRequest); if (StringUtils.isEmpty(ticket)) { logger.debug("票证获取失败,票证为空!"); return null; } return new CasToken(ticket); } /** * 拒绝除了option以外的所有请求 **/ @Override public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) { return true; } return false; } @Override public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { // 获取ticket,如果不存在,直接返回false String ticket = getRequestTicket((HttpServletRequest) request); if (StringUtils.isEmpty(ticket)) { return false; } return this.executeLogin(request, response); } /** * 获取请求的ticket */ private String getRequestTicket(HttpServletRequest httpRequest) { // 从参数中获取ticket String ticket = httpRequest.getParameter(TICKET_PARAMETER); if (StringUtils.isEmpty(ticket)) { // 如果为空的话,则从header中获取参数 ticket = httpRequest.getHeader(TICKET_PARAMETER); } return ticket; } }
4、自定义casRealm
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashSet; import java.util.Set; /** * @author : xingsongtan@qq.com * @date : 12:00 2019/7/17 */ public class MyCasRealm extends CasRealm { private static Logger log = LoggerFactory.getLogger(MyCasRealm.class); /** * 在调用subject.login()时,首先调用此接口 */ @Override public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 调用父类的方法,然后授权用户 AuthenticationInfo authc = super.doGetAuthenticationInfo(token); // 获得用户名 String username = (String) authc.getPrincipals().getPrimaryPrincipal(); // TODO:这里应该从数据库中获取用户信息 return authc; } /** * 进行权限验证的时候,调用方法,将用户的权限信息写进SimpleAuthorizationInfo */ @Override public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 用户名称 log.info("进入了权限认证"); Object username = principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // TODO: 这里应该从数据库获取用户权限 Set<String> permission = new HashSet<>(); permission.add("sys:dept:list"); info.setStringPermissions(permission); return info; } }
6、进行shiroconfig配置
import com.ttcode.shiro.security.MyCasFilter; import com.ttcode.shiro.security.MyCasRealm; import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy; import org.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.cache.MemoryConstrainedCacheManager; 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.filter.authc.LogoutFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Value; 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的配置文件 * * @author : xingsongtan@qq.com * @date : 20:51 2019/7/18 */ @Configuration public class ShiroCasConfiguration { /** * 添加shiro的filter */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); filterRegistration.addInitParameter("targetFilterLifecycle", "true"); filterRegistration.setEnabled(true); filterRegistration.addUrlPatterns("/*"); return filterRegistration; } /** * 保证了shiro内部lifecycle函数bean的执行 */ @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 配置授权策略 */ @Bean(name = "authenticator") public ModularRealmAuthenticator modularRealmAuthenticator() { ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator(); authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); return authenticator; } @Bean(name = "casRealm") public MyCasRealm casRealm(@Value("${shiro.casServerUrlPrefix}") String casServerUrlPrefix, @Value("${shiro.shiroServerUrlPrefix}") String shiroServerUrlPrefix, @Value("${shiro.casFilterUrlPattern}") String casFilterUrlPattern) { MyCasRealm casRealm = new MyCasRealm(); // 认证通过后的默认角色 casRealm.setDefaultRoles("ROLE_USER"); // cas服务端地址前缀 casRealm.setCasServerUrlPrefix(casServerUrlPrefix); // 应用服务地址,用来接收cas服务端票证 casRealm.setCasService(shiroServerUrlPrefix + casFilterUrlPattern); return casRealm; } /** * 配置安全管理器 **/ @Bean(name = "securityManager") public DefaultWebSecurityManager defaultWebSecurityManager(ModularRealmAuthenticator authenticator, MyCasRealm casRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置授权策略,此步骤必须在设置realm的前面,不然会报错realm未配置 securityManager.setAuthenticator(authenticator); securityManager.setSubjectFactory(new CasSubjectFactory()); // 缓存管理器 securityManager.setCacheManager(new MemoryConstrainedCacheManager()); // 设置自定义验证策略 securityManager.setRealm(casRealm); return securityManager; } /** * 配置登录过滤器 */ @Bean(name = "casFilter") public MyCasFilter casFilter(@Value("${shiro.loginUrl}") String loginUrl) { MyCasFilter casFilter = new MyCasFilter(); casFilter.setName("casFilter"); casFilter.setEnabled(true); casFilter.setFailureUrl(loginUrl); return casFilter; } /** * shiro 过滤器 */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager, MyCasFilter casFilter, @Value("${shiro.logoutUrl}") String logoutUrl, @Value("${shiro.loginUrl}") String loginUrl, @Value("${shiro.casFilterUrlPattern}") String casFilterUrlPattern) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置登录地址 shiroFilterFactoryBean.setLoginUrl(loginUrl); // 设置登录成功地址 shiroFilterFactoryBean.setSuccessUrl("/"); // 配置拦截地址 Map<String, Filter> filters = new HashMap<>(); filters.put("casFilter", casFilter); LogoutFilter logoutFilter = new LogoutFilter(); // 配置登出地址 logoutFilter.setRedirectUrl(logoutUrl); filters.put("logout", logoutFilter); shiroFilterFactoryBean.setFilters(filters); // 设置访问用户页面需要授权的操作 loadShiroFilterChain(shiroFilterFactoryBean, casFilterUrlPattern); // 将设置的权限设置到shiroFilterFactoryBean return shiroFilterFactoryBean; } /** * 1、当我们第一次访问客户端时,先去cas进行认证,成功后会返回一个ticket * 2、返回的ticket地址在casRealm已经进行了配置,shiroServerUrlPrefix + casFilterUrlPattern * 3、即地址为/shiro-cas,对该地址进行casFilter拦截 */ private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean, String casFilterUrlPattern) { Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put(casFilterUrlPattern, "casFilter"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); } /** * 开启Shiro的注解(如@RequiresPermissions) * 需借助SpringAOP扫描使用Shiro注解的类 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能 * * @return */ @Bean public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } /** * 开启aop注解支持 * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
结尾:以上为核心配置
源码地址
相关文章推荐
- spring boot 整合shiro和redis实现权限管理和登录功能
- SpringBoot2.0整合Shiro框架实现用户权限管理的示例
- 七、spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- springboot(十四):springboot整合shiro-登录认证和权限管理(转)
- 转载:Spring Boot (十四):springboot整合shiro-登录认证和权限管理
- SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例
- spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- springboot(十四):springboot整合shiro-登录认证和权限管理
- spring-boot(八) springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- Spring Boot (十四): Spring Boot 整合 Shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot 整合 shiro、JPA 、sqlserver实现权限管理
- springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理