spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
程序员文章站
2023-12-11 18:31:34
1.添加maven依赖(先安装好cas-server-3.5.2,安装步骤请查看本文参考文章)
<...
1.添加maven依赖(先安装好cas-server-3.5.2,安装步骤请查看本文参考文章)
<dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-spring</artifactid> <version>1.2.4</version> </dependency> <dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-ehcache</artifactid> <version>1.2.4</version> </dependency> <dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-cas</artifactid> <version>1.2.4</version> </dependency>
2.启动累添加@servletcomponentscan注解
@springbootapplication public class application { /** * main function * @param args params */ public static void main(string[] args){ configurableapplicationcontext context = springapplication.run(application.class,args); //test if a xml bean inject into springcontext successful user user = (user)context.getbean("user1"); system.out.println(jsonobject.tojsonstring(user)); } }
3.配置shiro+cas
package com.hdwang.config.shirocas; import com.hdwang.dao.userdao; 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.filter.authc.logoutfilter; 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.core.ordered; import org.springframework.web.filter.delegatingfilterproxy; import javax.servlet.filter; import javax.servlet.annotation.weblistener; import java.util.hashmap; import java.util.linkedhashmap; import java.util.map; /** * created by hdwang on 2017/6/20. * shiro+cas 配置 */ @configuration public class shirocasconfiguration { private static final logger logger = loggerfactory.getlogger(shirocasconfiguration.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:8081"; // casfilter urlpattern public static final string casfilterurlpattern = "/cas"; // 登录地址 public static final string loginurl = casloginurl + "?service=" + shiroserverurlprefix + casfilterurlpattern; // 登出地址 public static final string logouturl = caslogouturl+"?service="+shiroserverurlprefix; // 登录成功地址 public static final string loginsuccessurl = "/home"; // 权限认证失败跳转地址 public static final string unauthorizedurl = "/error/403.html"; @bean public ehcachemanager getehcachemanager() { ehcachemanager em = new ehcachemanager(); em.setcachemanagerconfigfile("classpath:ehcache-shiro.xml"); return em; } @bean(name = "myshirocasrealm") public myshirocasrealm myshirocasrealm(ehcachemanager cachemanager) { myshirocasrealm realm = new myshirocasrealm(); realm.setcachemanager(cachemanager); //realm.setcasserverurlprefix(shirocasconfiguration.casserverurlprefix); // 客户端回调地址 //realm.setcasservice(shirocasconfiguration.shiroserverurlprefix + shirocasconfiguration.casfilterurlpattern); return realm; } /** * 注册单点登出listener * @return */ @bean public servletlistenerregistrationbean singlesignouthttpsessionlistener(){ servletlistenerregistrationbean bean = new servletlistenerregistrationbean(); bean.setlistener(new singlesignouthttpsessionlistener()); // bean.setname(""); //默认为bean name bean.setenabled(true); //bean.setorder(ordered.highest_precedence); //设置优先级 return bean; } /** * 注册单点登出filter * @return */ @bean public filterregistrationbean singlesignoutfilter(){ filterregistrationbean bean = new filterregistrationbean(); bean.setname("singlesignoutfilter"); bean.setfilter(new singlesignoutfilter()); bean.addurlpatterns("/*"); bean.setenabled(true); //bean.setorder(ordered.highest_precedence); return bean; } /** * 注册delegatingfilterproxy(shiro) * * @return * @author shanhy * @create 2016年1月13日 */ @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(myshirocasrealm myshirocasrealm) { defaultwebsecuritymanager dwsm = new defaultwebsecuritymanager(); dwsm.setrealm(myshirocasrealm); // <!-- 用户授权/认证信息cache, 采用ehcache 缓存 --> dwsm.setcachemanager(getehcachemanager()); // 指定 subjectfactory dwsm.setsubjectfactory(new cassubjectfactory()); return dwsm; } @bean public authorizationattributesourceadvisor getauthorizationattributesourceadvisor(defaultwebsecuritymanager securitymanager) { authorizationattributesourceadvisor aasa = new authorizationattributesourceadvisor(); aasa.setsecuritymanager(securitymanager); return aasa; } /** * cas过滤器 * * @return * @author shanhy * @create 2016年1月17日 */ @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<br/> * 注意这里参数中的 studentservice 和 iscoredao 只是一个例子,因为我们在这里可以用这样的方式获取到相关访问数据库的对象, * 然后读取数据库相关配置,配置到 shirofilterfactorybean 的访问规则中。实际项目中,请使用自己的service来处理业务逻辑。 * * @param securitymanager * @param casfilter * @param userdao * @return * @author shanhy * @create 2016年1月14日 */ @bean(name = "shirofilter") public shirofilterfactorybean getshirofilterfactorybean(defaultwebsecuritymanager securitymanager, casfilter casfilter, userdao userdao) { 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); // filters.put("logout",logoutfilter()); shirofilterfactorybean.setfilters(filters); loadshirofilterchain(shirofilterfactorybean, userdao); return shirofilterfactorybean; } /** * 加载shirofilter权限控制规则(从数据库读取然后配置),角色/权限信息由myshirocasrealm对象提供dogetauthorizationinfo实现获取来的 * * @author shanhy * @create 2016年1月14日 */ private void loadshirofilterchain(shirofilterfactorybean shirofilterfactorybean, userdao userdao){ /////////////////////// 下面这些规则配置最好配置到配置文件中 /////////////////////// 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"); //filterchaindefinitionmap.put("/logout","logout"); //logut请求采用logout filter //2.不拦截的请求 filterchaindefinitionmap.put("/css/**","anon"); filterchaindefinitionmap.put("/js/**","anon"); filterchaindefinitionmap.put("/login", "anon"); filterchaindefinitionmap.put("/logout","anon"); filterchaindefinitionmap.put("/error","anon"); //3.拦截的请求(从本地数据库获取或者从casserver获取(webservice,http等远程方式),看你的角色权限配置在哪里) filterchaindefinitionmap.put("/user", "authc"); //需要登录 filterchaindefinitionmap.put("/user/add/**", "authc,roles[admin]"); //需要登录,且用户角色为admin filterchaindefinitionmap.put("/user/delete/**", "authc,perms[\"user:delete\"]"); //需要登录,且用户有权限为user:delete //4.登录过的不拦截 filterchaindefinitionmap.put("/**", "user"); shirofilterfactorybean.setfilterchaindefinitionmap(filterchaindefinitionmap); } }
package com.hdwang.config.shirocas; import javax.annotation.postconstruct; import com.hdwang.dao.userdao; import com.hdwang.entity.user; 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 java.util.hashset; import java.util.set; /** * created by hdwang on 2017/6/20. * 安全数据源 */ public class myshirocasrealm extends casrealm{ private static final logger logger = loggerfactory.getlogger(myshirocasrealm.class); @autowired private userdao userdao; @postconstruct public void initproperty(){ // setdefaultroles("role_user"); setcasserverurlprefix(shirocasconfiguration.casserverurlprefix); // 客户端回调地址 setcasservice(shirocasconfiguration.shiroserverurlprefix + shirocasconfiguration.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; // } /** * 权限认证,为当前登录的subject授予角色和权限 * @see 经测试:本例中该方法的调用时机为需授权资源被访问时 * @see 经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例中默认并未启用authorizationcache * @see 经测试:如果连续访问同一个url(比如刷新),该方法不会被重复调用,shiro有一个时间间隔(也就是cache时间,在ehcache-shiro.xml中配置),超过这个时间间隔再刷新页面,该方法会被执行 */ @override protected authorizationinfo dogetauthorizationinfo(principalcollection principalcollection) { logger.info("##################执行shiro权限认证##################"); //获取当前登录输入的用户名,等价于(string) principalcollection.fromrealm(getname()).iterator().next(); string loginname = (string)super.getavailableprincipal(principalcollection); //到数据库查是否有此对象(1.本地查询 2.可以远程查询casserver 3.可以由casserver带过来角色/权限其它信息) user user=userdao.getbyname(loginname);// 实际项目中,这里可以根据实际情况做缓存,如果不做,shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 if(user!=null){ //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission) simpleauthorizationinfo info=new simpleauthorizationinfo(); //给用户添加角色(让shiro去验证) set<string> rolenames = new hashset<>(); if(user.getname().equals("boy5")){ rolenames.add("admin"); } info.setroles(rolenames); if(user.getname().equals("李四")){ //给用户添加权限(让shiro去验证) info.addstringpermission("user:delete"); } // 或者按下面这样添加 //添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色 // simpleauthorinfo.addrole("admin"); //添加权限 // simpleauthorinfo.addstringpermission("admin:manage"); // logger.info("已为用户[mike]赋予了[admin]角色和[admin:manage]权限"); return info; } // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedurl指定的地址 return null; } }
package com.hdwang.controller; import com.hdwang.config.shirocas.shirocasconfiguration; import com.hdwang.entity.user; 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 hdwang on 2017/6/21. * 跳转至cas server去登录(一个入口) */ @controller @requestmapping("") public class caslogincontroller { /** * 一般用不到 * @param model * @return */ @requestmapping(value="/login",method= requestmethod.get) public string loginform(model model){ model.addattribute("user", new user()); // return "login"; return "redirect:" + shirocasconfiguration.loginurl; } @requestmapping(value = "logout", method = { requestmethod.get, requestmethod.post }) public string loginout(httpsession session) { return "redirect:"+shirocasconfiguration.logouturl; } }
package com.hdwang.controller; import com.alibaba.fastjson.jsonobject; import com.hdwang.entity.user; import com.hdwang.service.datajpa.userservice; import org.apache.shiro.securityutils; import org.apache.shiro.mgt.securitymanager; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.controller; import org.springframework.ui.modelmap; import org.springframework.web.bind.annotation.requestmapping; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpsession; /** * created by hdwang on 2017/6/19. */ @controller @requestmapping("/home") public class homecontroller { @autowired userservice userservice; @requestmapping("") public string index(httpsession session, modelmap map, httpservletrequest request){ // user user = (user) session.getattribute("user"); system.out.println(request.getuserprincipal().getname()); system.out.println(securityutils.getsubject().getprincipal()); user loginuser = userservice.getloginuser(); system.out.println(jsonobject.tojsonstring(loginuser)); map.put("user",loginuser); return "home"; } }
4.运行验证
登录
访问:
跳转至:
输入正确用户名密码登录跳转回:http://localhost:8081/cas?ticket=st-203-guhen64mozec9iwzsh1b-cas01.example.org
最终跳回:
登出
访问:
跳转至:
由于未登录,又执行登录步骤,所以最终返回
这次登录成功后返回:
cas server端登出(也行)
访问:
再访问: 会跳转至登录页,perfect!
以上所述是小编给大家介绍的spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制,希望对大家有所帮助