springboot+shiro+cas实现单点登录之shiro端搭建
2017-08-11 17:29
1121 查看
github:https://github.com/peterowang/shiro-cas
本文如有配置问题,请查看之前的springboot集成shiro的文章
1.配置ehcache缓存,在resource下创建config,再创建ehcache-shiro.xml添加:
运行验证
登录
访问:http://localhost:8089
跳转至:https://localhost:8443/cas/login?service=http://localhost:8089/cas
输入正确用户名密码登录跳转回:http://localhost:8089/cas?ticket=ST-203-GUheN64mOZec9IWZSH1B-cas01.example.org
最终跳回:http://localhost:8089/index
登出
访问:http://localhost:8089/logout
跳转至:https://localhost:8443/cas/logout?service=http://localhost:8089/cas
这次登录成功后返回:http://localhost:8089/index
本文如有配置问题,请查看之前的springboot集成shiro的文章
1.配置ehcache缓存,在resource下创建config,再创建ehcache-shiro.xml添加:
<?xml version="1.0" encoding="UTF-8"?> <ehcache updateCheck="false" name="shiroCache"> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /> </ehcache> 2.添加maven依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cas</artifactId> <version>1.2.4</version> </dependency> 3.配置shiro+cas 添加
MyShiroCasRealm 类
package com.example.demo.config.shiro; import com.example.demo.model.UserInfo; import org.apache.shiro.SecurityUtils; 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 org.springframework.beans.factory.annotation.Autowired; import javax.annotation.PostConstruct; /** * Created by BFD-593 on 2017/8/11. */ public class MyShiroCasRealm extends CasRealm { private static final Logger logger = LoggerFactory.getLogger(MyShiroCasRealm.class); @PostConstruct public void initProperty(){ // cas地址 setCasServerUrlPrefix(ShiroConfiguration.casServerUrlPrefix); // 客户端回调地址 setCasService(ShiroConfiguration.shiroServerUrlPrefix + ShiroConfiguration.casFilterUrlPattern); } // /** // * 1、CAS认证 ,验证用户身份 // * 2、将用户基本信息设置到会话中(不用了,随时可以获取的) // */ // @Override // protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { // // AuthenticationInfo authc = super.doGetAuthenticationInfo(token); // // String account = (String) authc.getPrincipals().getPrimaryPrincipal(); // // User user = userDao.getByName(account); // //将用户信息存入session中 // SecurityUtils.getSubject().getSession().setAttribute("user", user); // // return authc; // } /** * 此方法调用 hasRole,hasPermission的时候才会进行回调. * * 权限信息.(授权): 1、如果用户正常退出,缓存自动清空; 2、如果用户非正常退出,缓存自动清空; * 3、如果我们修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。 (需要手动编程进行实现;放在service进行调用) * 在权限修改后调用realm中的方法,realm已经由spring管理,所以从spring中获取realm实例, 调用clearCached方法; * :Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。 * * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { logger.info("开始权限配置"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); // UserInfo userInfo = (UserInfo)principals.getPrimaryPrincipal(); //这里应该查询数据库,拿到用户的所有角色,遍历添加角色到权限对象中,再通过角色获取权限,添加到权限对象中 /* for (Role role: userInfo.getRoleList()) { authorizationInfo.addRole(role.getRole()); for (SysPermission p: role.getPermissions()) { authorizationInfo.addStringPermission(p.getPermission()); } }*/ //为了节省时间,这边我先给它写死,做测试 authorizationInfo.addRole("wangjing"); authorizationInfo.addStringPermission("userinfo:view"); return authorizationInfo; } } 添加shiro配置类,主要是将casFilter添加到shiroFilter中
package com.example.demo.config.shiro; 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.jasig.cas.client.session.SingleSignOutFilter; import org.jasig.cas.client.session.SingleSignOutHttpSessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; import javax.servlet.Filter; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; /** * shiro配置类 * Created by BFD-593 on 2017/8/8. */ @Configuration public class ShiroConfiguration { private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class); // cas server地址 public static final String casServerUrlPrefix = "https://localhost:8443/cas"; // Cas登录页面地址 public static final String casLoginUrl = casServerUrlPrefix + "/login"; // Cas登出页面地址 public static final String casLogoutUrl = casServerUrlPrefix + "/logout"; // 当前工程对外提供的服务地址 public static final String shiroServerUrlPrefix = "http://localhost:8089"; // casFilter UrlPattern public static final String casFilterUrlPattern = "/cas"; // 登录地址 public static final String loginUrl = casLoginUrl + "?service=" + shiroServerUrlPrefix + casFilterUrlPattern; // 登出地址(casserver启用service跳转功能,需在webapps\cas\WEB-INF\cas.properties文件中启用cas.logout.followServiceRedirects=true) public static final String logoutUrl = casLogoutUrl+"?service="+shiroServerUrlPrefix; // 登录成功地址 public static final String loginSuccessUrl = "/index"; // 权限认证失败跳转地址 public static final String unauthorizedUrl = "/403"; @Bean public EhCacheManager getEhCacheManager() { EhCacheManager em = new EhCacheManager(); em.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml"); return em; } @Bean(name = "myShiroCasRealm") public MyShiroCasRealm myShiroCasRealm(EhCacheManager cacheManager) { MyShiroCasRealm realm = new MyShiroCasRealm(); realm.setCacheManager(cacheManager); return realm; } /** * 注册单点登出listener * @return */ @Bean public ServletListenerRegistrationBean singleSignOutHttpSessionListener(){ ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(); bean.setListener(new SingleSignOutHttpSessionListener()); bean.setEnabled(true); return bean; } /** * 注册单点登出filter * @return */ @Bean public FilterRegistrationBean singleSignOutFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setName("singleSignOutFilter"); bean.setFilter(new SingleSignOutFilter()); bean.addUrlPatterns("/*"); bean.setEnabled(true); return bean; } /** * 注册DelegatingFilterProxy(Shiro) */ @Bean public FilterRegistrationBean delegatingFilterProxy() { 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 getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator(); daap.setProxyTargetClass(true); return daap; } @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myShiroCasRealm") MyShiroCasRealm myShiroCasRealm) { DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager(); dwsm.setRealm(myShiroCasRealm); //用户授权/认证信息Cache, 采用EhCache 缓存 dwsm.setCacheManager(getEhCacheManager()); // 指定 SubjectFactory dwsm.setSubjectFactory(new CasSubjectFactory()); return dwsm; } /** * CAS过滤器 * * @return */ @Bean(name = "casFilter") public CasFilter getCasFilter() { CasFilter casFilter = new CasFilter(); casFilter.setName("casFilter"); casFilter.setEnabled(true); // 登录失败后跳转的URL,也就是 Shiro 执行 CasRealm 的 doGetAuthenticationInfo 方法向CasServer验证tiket casFilter.setFailureUrl(loginUrl);// 我们选择认证失败后再打开登录页面 return casFilter; } /** * ShiroFilter * @param securityManager * @param casFilter * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager, @Qualifier("casFilter") CasFilter casFilter) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl(loginUrl); // 登录成功后要跳转的连接 shiroFilterFactoryBean.setSuccessUrl(loginSuccessUrl); shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); // 添加casFilter到shiroFilter中 Map<String, Filter> filters = new HashMap<>(); filters.put("casFilter", casFilter); shiroFilterFactoryBean.setFilters(filters); loadShiroFilterChain(shiroFilterFactoryBean); return shiroFilterFactoryBean; } /** * 加载shiroFilter权限控制规则(从数据库读取然后配置),角色/权限信息由MyShiroCasRealm对象提供doGetAuthorizationInfo实现获取来的 */ private void loadShiroFilterChain(@Qualifier("shiroFilter") ShiroFilterFactoryBean shiroFilterFactoryBean){ /////////////////////// 下面这些规则配置最好配置到配置文件中 /////////////////////// Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // authc:该过滤器下的页面必须登录后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter // anon: 可以理解为不拦截 // user: 登录了就不拦截 // roles["admin"] 用户拥有admin角色 // perms["permission1"] 用户拥有permission1权限 // filter顺序按照定义顺序匹配,匹配到就验证,验证完毕结束。 // url匹配通配符支持:? * **,分别表示匹配1个,匹配0-n个(不含子路径),匹配下级所有路径 //1.shiro集成cas后,首先添加该规则 filterChainDefinitionMap.put(casFilterUrlPattern, "casFilter"); //2.不拦截的请求 filterChainDefinitionMap.put("/css/**","anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/logout","anon"); filterChainDefinitionMap.put("/error","anon"); //3.拦截的请求,并且拥有哪些权限才可以访问,当没有权限时 // 我们通过在shiroFilter里设置 shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); // 让其跳转到403页面,需要加403的controller请求哦 // 这里还可以通过另一种方式,就是在controller的需要的请求上,加shiro的权限注解 // 如果通过注解的方式,则需要通过以下两个配置bean来分别设置支持shiro注解和无权限跳转的页面 filterChainDefinitionMap.put("/userinfo/userList", "authc,perms[\"userinfo:view\"],roles[\"wangjing\"]"); //需要登录,且用户有权限为userinfo:view并且角色为wangjing filterChainDefinitionMap.put("/userinfo/userDel", "authc,perms[\"userinfo:view\"],roles[\"admin\"]"); filterChainDefinitionMap.put("/userinfo/userAdd", "authc,perms[\"userinfo:view\"],roles[\"redhat\"]"); //4.登录过的不拦截 filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); } /* *//** * 权限认证 * 需要开启Shiro AOP注解支持 * @RequiresPermissions({"userinfo:view"}) * @RequiresRoles({"wangjing"})等注解的支持 * @param securityManager * @return *//* @Bean public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor(); aasa.setSecurityManager(securityManager); return aasa; }*/ /** * 当用户无权限访问403页面而不抛异常,默认shiro会报UnauthorizedException异常 * @return */ /* @Bean public SimpleMappingExceptionResolver resolver() { SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties properties = new Properties(); properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/403"); resolver.setExceptionMappings(properties); return resolver; }*/ } 添加HomeController
package com.example.demo.web; import com.example.demo.config.shiro.ShiroConfiguration; import com.example.demo.model.UserInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpSession; /** * Created by BFD-593 on 2017/8/8. */ @Controller public class HomeController { private static final Logger log = LoggerFactory.getLogger(HomeController.class); @RequestMapping({"/","/index"}) public String index() { return "index"; } /** * shiroFilterFactoryBean.setLoginUrl(loginUrl);我们设置了登录地址,但没设置logout, * 所以加一个logout的请求,转到cas的logout上 * @param session * @return */ @RequestMapping(value = "logout", method = { RequestMethod.GET, RequestMethod.POST }) public String loginout(HttpSession session) { return "redirect:"+ShiroConfiguration.logoutUrl; } @RequestMapping("/403") public String fail(){ return "403"; } } 添加UserController
package com.example.demo.web; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresUser; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * Created by BFD-593 on 2017/8/9. */ @Controller @RequestMapping("/userinfo") public class UserController { /** * 要查看必须有角色wangjing和有权限userinfo:view * @return */ @RequestMapping("/userList") public String userInfo(){ return "userInfo"; } /** * 用户添加必须有查看和删除权限; * @return */ @RequestMapping("/userAdd") public String userInfoAdd(){ return "userAdd"; } /** * 要删除必须有查看和删除权限 * @return */ @RequestMapping("/userDel") public String userInfoDel() { return "userDel"; } }
运行验证
登录
访问:http://localhost:8089
跳转至:https://localhost:8443/cas/login?service=http://localhost:8089/cas
输入正确用户名密码登录跳转回:http://localhost:8089/cas?ticket=ST-203-GUheN64mOZec9IWZSH1B-cas01.example.org
最终跳回:http://localhost:8089/index
登出
访问:http://localhost:8089/logout
跳转至:https://localhost:8443/cas/logout?service=http://localhost:8089/cas
这次登录成功后返回:http://localhost:8089/index
相关文章推荐
- springboot+shiro+cas实现单点登录之cas server搭建
- 七、spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
- shiro+cas+spring-data-redis实现多系统单点登录和分布式项目的session同步
- spring boot整合Shiro实现单点登录的示例代码
- 基于springboot的shiro sso统一登录系统平台搭建遇到的坑
- cas shiro spring实现单点登录
- springboot整合shiro登录失败次数限制功能的实现代码
- spring boot配置shiro安全框架及用户登录权限验证实现
- spring + shiro + cas 实现sso单点登录的示例代码
- spring + shiro + cas 实现sso单点登录
- spring + shiro + cas 实现sso单点登录
- spring + shiro + cas 实现sso单点登录
- SpringBoot整合Shiro实现登录认证的方法
- spring + shiro + cas 实现sso单点登录
- 用shiro+springboot+mybatis实现禁止账号重复登录
- 基于CAS的单点登录SSO[5]: 基于Springboot实现CAS客户端的前后端分离
- springboot+shiro实现登录系数限定,thymeleaf中使用shiro标签
- spring boot整合Shiro实现单点登录
- spring + shiro + cas 实现sso单点登录