济公传 郭德纲,翡翠原始恐角龙,我要订货网
shiro是什么
shiro是一个java平台的开源权限框架,用于认证和访问授权。具体来说,满足对如下元素的支持:
q:对组的支持?
a:shiro默认不支持对组设置权限。
q:是否可以满足对组进行角色分配的需求?
a:扩展realm,可以支持对组进行分配角色,其实就是给该组下的所有用户分配权限。
q:对数据权限的支持? 在业务系统中定义?
a:shiro仅仅实现对操作权限的控制,用于在前端控制元素隐藏或者显示,以及对资源访问权限进行检查。数据权限与具体的业务需求紧密关联,shiro本身无法实现对数据权限的控制。
q:动态权限分配?
a:扩展org.apache.shiro.realm.realm,支持动态权限分配。
q:与spring集成?
a:可以支持与spring集成,shiro还支持jsp标签。
前面的博客中,我们说道了shiro的两个最大的特点,认证和授权,而单点登录也是属于认证的一部分,默认情况下,shiro已经为我们实现了和cas的集成,我们加入集成的一些配置就ok了。
1、加入shiro-cas包
<!-- shiro整合cas单点 --> <dependency> <groupid>org.apache.shiro</groupid> <artifactid>shiro-cas</artifactid> <version>1.2.4</version> </dependency>
2、加入单点登录的配置
这里,我将所有的配置都贴出来,方便参考,配置里面已经加了详尽的说明。
package com.chhliu.springboot.shiro.config; import java.util.linkedhashmap; import java.util.map; import javax.servlet.filter; 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.springframework.aop.framework.autoproxy.defaultadvisorautoproxycreator; 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.context.annotation.dependson; import org.springframework.core.ordered; import org.springframework.core.annotation.order; import org.springframework.web.filter.delegatingfilterproxy; /** * shiro 配置 * * apache shiro 核心通过 filter 来实现,就好像springmvc 通过dispachservlet 来主控制一样。 既然是使用 * filter 一般也就能猜到,是通过url规则来进行过滤和权限校验,所以我们需要定义一系列关于url的规则和访问权限。 * * @author chhliu */ @configuration public class shiroconfiguration { // cas server地址 public static final string casserverurlprefix = "http://127.0.0.1"; // cas登录页面地址 public static final string casloginurl = casserverurlprefix + "/login"; // cas登出页面地址 public static final string caslogouturl = casserverurlprefix + "/logout"; // 当前工程对外提供的服务地址 public static final string shiroserverurlprefix = "http://127.0.1.28:8080"; // casfilter urlpattern public static final string casfilterurlpattern = "/index"; // 登录地址 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="+loginurl; // 登录成功地址 // public static final string loginsuccessurl = "/index"; // 权限认证失败跳转地址 public static final string unauthorizedurl = "/error/403.html"; /** * 实例化securitymanager,该类是shiro的核心类 * @return */ @bean public defaultwebsecuritymanager securitymanager() { defaultwebsecuritymanager securitymanager = new defaultwebsecuritymanager(); securitymanager.setrealm(myshirocasrealm()); // <!-- 用户授权/认证信息cache, 采用ehcache 缓存 --> securitymanager.setcachemanager(getehcachemanager()); // 指定 subjectfactory,如果要实现cas的remember me的功能,需要用到下面这个cassubjectfactory,并设置到securitymanager的subjectfactory中 securitymanager.setsubjectfactory(new cassubjectfactory()); return securitymanager; } /** * 配置缓存 * @return */ @bean public ehcachemanager getehcachemanager() { ehcachemanager em = new ehcachemanager(); em.setcachemanagerconfigfile("classpath:config/ehcache-shiro.xml"); return em; } /** * 配置realm,由于我们使用的是casrealm,所以已经集成了单点登录的功能 * @param cachemanager * @return */ @bean public myshirorealm myshirocasrealm() { myshirorealm realm = new myshirorealm(); // cas登录服务器地址前缀 realm.setcasserverurlprefix(shiroconfiguration.casserverurlprefix); // 客户端回调地址,登录成功后的跳转地址(自己的服务地址) realm.setcasservice(shiroconfiguration.shiroserverurlprefix + shiroconfiguration.casfilterurlpattern); // 登录成功后的默认角色,此处默认为user角色 realm.setdefaultroles("user"); return realm; } /** * 注册单点登出的listener * @return */ @suppresswarnings({ "rawtypes", "unchecked" }) @bean @order(ordered.highest_precedence)// 优先级需要高于cas的filter 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; } /** * 该类可以保证实现了org.apache.shiro.util.initializable接口的shiro对象的init或者是destory方法被自动调用, * 而不用手动指定init-method或者是destory-method方法 * 注意:如果使用了该类,则不需要手动指定初始化方法和销毁方法,否则会出错 * @return */ @bean(name = "lifecyclebeanpostprocessor") public lifecyclebeanpostprocessor getlifecyclebeanpostprocessor() { return new lifecyclebeanpostprocessor(); } /** * 下面两个配置主要用来开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持; * @return */ @bean @dependson("lifecyclebeanpostprocessor") public defaultadvisorautoproxycreator getdefaultadvisorautoproxycreator() { defaultadvisorautoproxycreator daap = new defaultadvisorautoproxycreator(); daap.setproxytargetclass(true); return daap; } /** * @param securitymanager * @return */ @bean public authorizationattributesourceadvisor getauthorizationattributesourceadvisor(defaultwebsecuritymanager securitymanager) { authorizationattributesourceadvisor authorizationattributesourceadvisor = new authorizationattributesourceadvisor(); authorizationattributesourceadvisor.setsecuritymanager(securitymanager); return authorizationattributesourceadvisor; } /** * 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);// 我们选择认证失败后再打开登录页面 casfilter.setloginurl(loginurl); return casfilter; } /** * 使用工厂模式,创建并初始化shirofilter * @param securitymanager * @param casfilter * @return */ @bean(name = "shirofilter") public shirofilterfactorybean getshirofilterfactorybean(defaultwebsecuritymanager securitymanager, casfilter casfilter) { shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean(); // 必须设置 securitymanager shirofilterfactorybean.setsecuritymanager(securitymanager); // 如果不设置默认会自动寻找web工程根目录下的"/login.jsp"页面 shirofilterfactorybean.setloginurl(loginurl); /* * 登录成功后要跳转的连接,不设置的时候,会默认跳转到前一步的url * 比如先在浏览器中输入了http://localhost:8080/userlist,但是现在用户却没有登录,于是会跳转到登录页面,等登录认证通过后, * 页面会再次自动跳转到http://localhost:8080/userlist页面而不是登录成功后的index页面 * 建议不要设置这个字段 */ // shirofilterfactorybean.setsuccessurl(loginsuccessurl); // 设置无权限访问页面 shirofilterfactorybean.setunauthorizedurl(unauthorizedurl); /* * 添加casfilter到shirofilter中,注意,casfilter需要放到shirofilter的前面, * 从而保证程序在进入shiro的login登录之前就会进入单点认证 */ map<string, filter> filters = new linkedhashmap<>(); filters.put("casfilter", casfilter); // logout已经被单点登录的logout取代 // filters.put("logout",logoutfilter()); shirofilterfactorybean.setfilters(filters); loadshirofilterchain(shirofilterfactorybean); return shirofilterfactorybean; } /** * 加载shirofilter权限控制规则(从数据库读取然后配置),角色/权限信息由myshirocasrealm对象提供dogetauthorizationinfo实现获取来的 * 生产中会将这部分规则放到数据库中 * @param shirofilterfactorybean */ private void loadshirofilterchain(shirofilterfactorybean shirofilterfactorybean){ /////////////////////// 下面这些规则配置最好配置到配置文件中,注意,此处加入的filter需要保证有序,所以用的linkedhashmap /////////////////////// map<string, string> filterchaindefinitionmap = new linkedhashmap<string, string>(); filterchaindefinitionmap.put(casfilterurlpattern, "casfilter"); //2.不拦截的请求 filterchaindefinitionmap.put("/css/**","anon"); filterchaindefinitionmap.put("/js/**","anon"); filterchaindefinitionmap.put("/login", "anon"); // 此处将logout页面设置为anon,而不是logout,因为logout被单点处理,而不需要再被shiro的logoutfilter进行拦截 filterchaindefinitionmap.put("/logout","anon"); filterchaindefinitionmap.put("/error","anon"); //3.拦截的请求(从本地数据库获取或者从casserver获取(webservice,http等远程方式),看你的角色权限配置在哪里) filterchaindefinitionmap.put("/user", "authc"); //需要登录 //4.登录过的不拦截 filterchaindefinitionmap.put("/**", "authc"); shirofilterfactorybean.setfilterchaindefinitionmap(filterchaindefinitionmap); } }
部分配置参考:
3、编写realm
由于需要集成单点登录的功能,所以需要集成casrealm类,该类已经为我们实现了单点认证的功能,我们要做的就是实现授权部分的功能,示例代码如下:
package com.chhliu.springboot.shiro.config; import javax.annotation.resource; 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 com.chhliu.springboot.shiro.mode.syspermission; import com.chhliu.springboot.shiro.mode.sysrole; import com.chhliu.springboot.shiro.mode.userinfo; import com.chhliu.springboot.shiro.service.userinfoservice; /** * 权限校验核心类; 由于使用了单点登录,所以无需再进行身份认证 只需要授权即可 * * @author chhliu */ public class myshirorealm extends casrealm { @resource private userinfoservice userinfoservice; /** * 1、cas认证 ,验证用户身份 * 2、将用户基本信息设置到会话中,方便获取 * 3、该方法可以直接使用casrealm中的认证方法,此处仅用作测试 */ @override protected authenticationinfo dogetauthenticationinfo(authenticationtoken token) { // 调用父类中的认证方法,casrealm已经为我们实现了单点认证。 authenticationinfo authc = super.dogetauthenticationinfo(token); // 获取登录的账号,cas认证成功后,会将账号存起来 string account = (string) authc.getprincipals().getprimaryprincipal(); // 将用户信息存入session中,方便程序获取,此处可以将根据登录账号查询出的用户信息放到session中 securityutils.getsubject().getsession().setattribute("no", account); return authc; } /** * 此方法调用 hasrole,haspermission的时候才会进行回调. * * 权限信息.(授权): 1、如果用户正常退出,缓存自动清空; 2、如果用户非正常退出,缓存自动清空; * 3、如果我们修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。 (需要手动编程进行实现;放在service进行调用) * 在权限修改后调用realm中的方法,realm已经由spring管理,所以从spring中获取realm实例, 调用clearcached方法; * :authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。 * * @param principals * @return */ @override protected authorizationinfo dogetauthorizationinfo(principalcollection principals) { system.out.println("权限配置-->myshirorealm.dogetauthorizationinfo()"); simpleauthorizationinfo authorizationinfo = new simpleauthorizationinfo(); // 获取单点登陆后的用户名,也可以从session中获取,因为在认证成功后,已经将用户名放到session中去了 string username = (string) super.getavailableprincipal(principals); // principals.getprimaryprincipal(); 这种方式也可以获取用户名 // 根据用户名获取该用户的角色和权限信息 userinfo userinfo = userinfoservice.findbyusername(username); // 将用户对应的角色和权限信息打包放到authorizationinfo中 for (sysrole role : userinfo.getrolelist()) { authorizationinfo.addrole(role.getrole()); for (syspermission p : role.getpermissions()) { authorizationinfo.addstringpermission(p.getpermission()); } } return authorizationinfo; } }
下面,我们就可以进行验证测试了!
在浏览器输入http:127.0.1.28:8080/userinfo/userlist 我们会发现,会自动跳转到单点的登录页面
然后我们输入用户名和密码,就会自动跳转到http:127.0.1.28:8080/userinfo/userlist页面了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
浅析我对 String、StringBuilder、StringBuffer 的理解
使用IDEA搭建SSM框架的详细教程(spring + springMVC +MyBatis)
Springboot整合freemarker 404问题解决方案
引入mybatis-plus报 Invalid bound statement错误问题的解决方法
网友评论