shiro框架---关于用户登录和权限验证功能的实现步骤(三)
2018-02-18 22:49
3235 查看
接上一篇文章shiro框架—关于用户登录和权限验证功能的实现步骤(二)
主要的文件有四个
以下是
下边针对于
首先该文件的第一个配置为
既然上边注入的是名字为
以上的
在当前的shiro框架中,无法拦截那种
在上边的配置中,其实就是自定义了一个shiro过滤器,然后对其进行了一些操作,其中
另外,
通过上边的
以上又引入了我们的第三个配置文件,即
在这里的
通过上边的
上边的配置,主要是对
以上配置起的名字为
以后再请求,只要浏览器没有清除
关于
如果出现
继续
上边有
另外,上边
这个
另外提到的另外三个配置文件,先不写了,放到下一篇吧,今天写的有点多了。先贴上shiro的这四个配置文件的下载地址shiro的配置
下一篇文章shiro框架—关于用户登录和权限验证功能的实现步骤(四)
shiro在springboot项目中的配置步骤
1、引入依赖
首先shiro的应用,引入的依赖仅仅只有一个,即下边这个。<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.3.2</version> </dependency>
2、shiro在springboot项目中的位置:
以下是shiro在springboot项目中的位置:主要的文件有四个
ShiroConfig、
RetryLimitHashedCredentialsMatcher、
UserRealm、
MShiroFilterFactoryBean。在这里
`UserOAuthMatcher没有用到,其实它跟
RetryLimitHashedCredentialsMatcher是一样的意思,都是实现的同一个shiro的接口,用哪一个都可以,我在下边的链接里就不放进
UserOAuthMatcher了。
3、以上配置文件的主要功能:
(1) shiroConfig以下是
shiroConfig文件的全部配置。其他的配置文件都是围绕这个文件展开工作的。
package microservice.fpzj.shiro; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.authc.AnonymousFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.web.filter.DelegatingFilterProxy; import javax.servlet.DispatcherType; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); filterRegistration.setEnabled(true); filterRegistration.addUrlPatterns("/*"); //过滤规则,即所有的请求 filterRegistration.setDispatcherTypes(DispatcherType.REQUEST); return filterRegistration; } /** * 这个即是上边调用的shiroFilter过滤器,也就是shiro配置的过滤器 * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(){ /** *MShiroFilterFactoryBean指向自定义过滤器,自定义过滤器对js/css等忽 *略 **/ ShiroFilterFactoryBean bean = new MShiroFilterFactoryBean(); bean.setSecurityManager(securityManager()); bean.setLoginUrl("/login"); bean.setUnauthorizedUrl("/unauthor"); Map<String, Filter>filters = new LinkedHashMap<>(); // filters.put("perms", urlPermissionsFilter()); filters.put("anon", new AnonymousFilter()); bean.setFilters(filters); //shiro配置过滤规则少量的话可以用hashMap,数量多了要用LinkedHashMap,保证有序,原因未知 Map<String, String> chains = new LinkedHashMap<>(); chains.put("/login", "anon"); chains.put("/unauthor", "anon"); chains.put("/logout", "anon"); chains.put("/weblogin", "anon"); chains.put("/**", "authc"); bean.setFilterChainDefinitionMap(chains); return bean; } /** * @see org.apache.shiro.mgt.SecurityManager * @return */ @Bean(name="securityManager") public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(userRealm()); //manager.setCacheManager(cacheManager()); manager.setSessionManager(defaultWebSessionManager()); return manager; } /** * @see DefaultWebSessionManager * @return */ @Bean(name="sessionManager") public DefaultWebSessionManager defaultWebSessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); //sessionManager.setCacheManager(cacheManager()); sessionManager.setGlobalSessionTimeout(1800000); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionValidationSchedulerEnabled(true); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionIdCookie(getSessionIdCookie()); return sessionManager; } /** * 给shiro的sessionId默认的JSSESSIONID名字改掉 * @return */ @Bean(name="sessionIdCookie") public SimpleCookie getSessionIdCookie(){ SimpleCookie simpleCookie = new SimpleCookie("webcookie"); /** * HttpOnly标志的引入是为了防止设置了该标志的cookie被JavaScript读取, * 但事实证明设置了这种cookie在某些浏览器中却能被JavaScript覆盖, * 可被攻击者利用来发动session fixation攻击 */ simpleCookie.setHttpOnly(true); /** * 设置浏览器cookie过期时间,如果不设置默认为-1,表示关闭浏览器即过期 * cookie的单位为秒 比如60*60为1小时 */ simpleCookie.setMaxAge(-1); return simpleCookie; } /** * @see UserRealm--->AuthorizingRealm * @return */ @Bean @DependsOn(value="lifecycleBeanPostProcessor") public UserRealm userRealm() { UserRealm userRealm = new UserRealm(); userRealm.setCredentialsMatcher(credentialsMatcher()); //userRealm.setCacheManager(cacheManager()); return userRealm; } @Bean(name="credentialsMatcher") public CredentialsMatcher credentialsMatcher() { return new RetryLimitHashedCredentialsMatcher(); } /*@Bean public EhCacheManager cacheManager() { EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml"); return cacheManager; }*/ @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } }
下边针对于
shiroConfig文件中的配置,一一说明。
首先该文件的第一个配置为
FilterRegistrationBean。 springboot注入过滤器有多种方式,一种是最简单的@WebFilter注解,一种就是下边的这种,写一个FilterRegistrationBean,然后将自定义过滤器set进去,下边是通过
DelegatingFilterProxy代理的方式,注入容器中名字为
shiroFilter的过滤器,最后设置过滤器的规则。
@Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); /** *DelegatingFilterProxy做的事情是代理Filter的方法,从application *context里获得bean,从下边可以理解到,它是将容器中名字为shiroFilter *的过滤器加入到过滤器注册bean中 **/ filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); filterRegistration.setEnabled(true); filterRegistration.addUrlPatterns("/*"); //过滤规则,即所有的请求 filterRegistration.setDispatcherTypes(DispatcherType.REQUEST); return filterRegistration; }
既然上边注入的是名字为
shiroFilter的过滤器,那下边就是
shiroFilter的配置
/** * 这个即是上边调用的shiroFilter过滤器,也就是shiro配置的过滤器 * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(){ /** *MShiroFilterFactoryBean指向自定义过滤器,自定义过滤器对js/css等忽 *略 **/ ShiroFilterFactoryBean bean = new MShiroFilterFactoryBean(); bean.setSecurityManager(securityManager()); bean.setLoginUrl("/login"); bean.setUnauthorizedUrl("/unauthor"); Map<String, Filter>filters = new LinkedHashMap<>(); // filters.put("perms", urlPermissionsFilter()); /** * shiro自己的过滤器,anon,表示不拦截的路径,authc,表示拦截的路径 **/ filters.put("anon", new AnonymousFilter()); bean.setFilters(filters); /* *shiro配置过滤规则少量的话可以用hashMap,数量多了要用 *LinkedHashMap,保证有序,原因未知。 *,anon,表示不拦截的路径,authc,表示拦截的路径。匹配时,首先匹配 *anon的,然后最后匹配authc **/ Map<String, String> chains = new LinkedHashMap<>(); chains.put("/login", "anon"); chains.put("/unauthor", "anon"); chains.put("/logout", "anon"); chains.put("/weblogin", "anon"); chains.put("/**", "authc"); bean.setFilterChainDefinitionMap(chains); return bean; }
以上的
shiroFilter配置中,又引入了我们的第二个配置文件,名字为
MShiroFilterFactoryBean,该类继承了
ShiroFilterFactoryBean类,通过名字,应该大体能知道,它是shiro的过滤器工厂类,而我们的
MShiroFilterFactoryBean类就是一个自定义的shiro过滤器,为什么要自己写一个过滤器呢?
在当前的shiro框架中,无法拦截那种
.js、
.css、
.html、
.jsp等等带有
.的请求路径,对于前三种这种静态资源,我们可以不纳入shiro拦截,即可以在不登录的情况下访问成功,但是我们现在有这样的需求,即对
.jsp也要拦截起来,那就需要自定义shiro过滤器了,即现在
MShiroFilterFactoryBean类存在的意义。关于该类的解释,在后边再说,我们继续
shiroConfig文件的介绍。
在上边的配置中,其实就是自定义了一个shiro过滤器,然后对其进行了一些操作,其中
bean.setLoginUrl("/login")是在项目启动后,如果没有登录的情况下,会被shiro强制请求的路径,即为
/login;
另外,
bean.setSecurityManager(securityManager());这句的配置,即引入设置shiro的控制中心,即
securityManager,安全管理器;即所有与安全有关的操作都会与
securityManager交互;且它管理着所有
Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;关于
subject,你就理解为是每一个访问系统的用户对象即可,所有的访问用户的情况都是一种
subject的体现,它们又统一被
securityManager管理,这个在第一篇里已经说过。
通过上边的
shiroFilter的配置之后,然后再看
securityManager。
/** * @see org.apache.shiro.mgt.SecurityManager * @return */ @Bean(name="securityManager") public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(userRealm()); //manager.setCacheManager(cacheManager()); manager.setSessionManager(defaultWebSessionManager()); return manager; }
以上又引入了我们的第三个配置文件,即
UserRealm文件,改文件又引出了我们的一个概念,
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
在这里的
UserRealm类继承于
AuthorizingRealm,该类的作用其实有用户密码验证、权限授权等。这个也会在后边贴出来,先继续讲
shiroConfig文件。
通过上边的
manager.setSessionManager(defaultWebSessionManager());然后引入下边的配置
/** * @see DefaultWebSessionManager * @return */ @Bean(name="sessionManager") public DefaultWebSessionManager defaultWebSessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); //sessionManager.setCacheManager(cacheManager()); sessionManager.setGlobalSessionTimeout(1800000); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionValidationSchedulerEnabled(true); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionIdCookie(getSessionIdCookie()); return sessionManager; }
上边的配置,主要是对
session的配置,比如,超时时间的设置等,基本上都是跟
session相关的配置。另外,上边还有
getSessionIdCookie()方法的引用,众所周知,浏览器与后台系统交互的方式,是以后台存储
session,然后将该
session对应key,以字符串的形式返给浏览器,并在浏览器中以
cookie的形式记录起来,方便后续的访问,如果浏览器丢失了这个
cookie,那就会失去与后台系统的联系,必须重新登录,才能重新再生成这个
cookie。而
getSessionIdCookie()方法,即是对cookie在浏览器那里的名字的定义,如下:
/** * 给shiro的sessionId默认的JSSESSIONID名字改掉 * @return */ @Bean(name="sessionIdCookie") public SimpleCookie getSessionIdCookie(){ SimpleCookie simpleCookie = new SimpleCookie("webcookie"); /** * HttpOnly标志的引入是为了防止设置了该标志的cookie被JavaScript读取, * 但事实证明设置了这种cookie在某些浏览器中却能被JavaScript覆盖, * 可被攻击者利用来发动session fixation攻击 */ simpleCookie.setHttpOnly(true); /** * 设置浏览器cookie过期时间,如果不设置默认为-1,表示关闭浏览器即过期 * cookie的单位为秒 比如60*60为1小时 */ simpleCookie.setMaxAge(-1); return simpleCookie; }
以上配置起的名字为
webcookie,这个
webcookie就是浏览器那边存储后台传入过来的
cookie的key。整个的大体流程,我理解的如下:
以后再请求,只要浏览器没有清除
cookie,上边关于
session的超时时间没有超时,就可以正常访问系统。之所以,这里要给
sessionid起一个名字
webcookie这是防止浏览器访问多个系统的时候,恰巧碰上两个系统在浏览器那边存储
sessionid对应的key正好相同,即
session污染,造成访问系统出现问题。如果不设置,shiro默认的
sessionid在前端浏览器的名字为
cookie。
关于
session污染的异常,我遇到的是下边这个:
Found 'sid' cookie value [1a22b751-0542-4e74-a8e7-59942692f6ae] 22:13:37 DEBUG net.sf.ehcache.Cache - mx-master-SessionCache cache - Miss 22:13:37 DEBUG o.a.shiro.mgt.DefaultSecurityManager - Resolved SubjectContext context session is invalid. Ignoring and creating an anonymous (session-less) Subject instance. org.apache.shiro.session.UnknownSessionException: There is no session with id [1a22b751-0542-4e74-a8e7-59942692f6ae]
如果出现
There is no session with id的异常,不出意外的话,就是上边的配置有问题,需要有
cookie的配置,相关的文章,你可以看这一篇一个项目两个web模块会导致shiro的session污染 ,可以得到解释。
继续
shiroconfig文件的配置,然后再后边就是如下配置:
@Bean @DependsOn(value="lifecycleBeanPostProcessor") public UserRealm userRealm() { UserRealm userRealm = new UserRealm(); userRealm.setCredentialsMatcher(credentialsMatcher()); //userRealm.setCacheManager(cacheManager()); return userRealm; } @Bean(name="credentialsMatcher") public CredentialsMatcher credentialsMatcher() { return new RetryLimitHashedCredentialsMatcher(); } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); }
上边有
userRealm类的注入,而在前边
securityManager的配置的时候,它引入了
userRealm,就是在这里对
userRealm类注入的。
另外,上边
userRealm方法中设置了一个
credentialsMatcher(),该方法对应的就是
new RetryLimitHashedCredentialsMatcher()类,这里就引入了我们第四个配置文件
RetryLimitHashedCredentialsMatcher类,该类,继承于
HashedCredentialsMatcher类,而
HashedCredentialsMatcher你如果往上找,其实就是实现了
CredentialsMatcher接口,所以这里注入的时候,可以以自定义的
RetryLimitHashedCredentialsMatcher类注入成
CredentialsMatcher,该类的功能主要是将用户输入的密码与查询到的密码进行比较,也就是密码比较器。
这个
shiroConfig类写的有点多,我理解的也有点不足,有些片面,如果有不对的地方,请读者帮我指正,我及时改过来。
另外提到的另外三个配置文件,先不写了,放到下一篇吧,今天写的有点多了。先贴上shiro的这四个配置文件的下载地址shiro的配置
下一篇文章shiro框架—关于用户登录和权限验证功能的实现步骤(四)
相关文章推荐
- shiro框架---关于用户登录和权限验证功能的实现步骤(一)
- shiro框架---关于用户登录和权限验证功能的实现步骤(四)
- shiro框架---关于用户登录和权限验证功能的实现步骤(七)
- shiro框架---关于用户登录和权限验证功能的实现步骤(五)
- shiro框架---关于用户登录和权限验证功能的实现步骤(八)
- shiro框架---关于用户登录和权限验证功能的实现步骤(六)
- shiro框架---关于用户登录和权限验证功能的实现步骤(二)
- 基于权限安全框架Shiro的登录验证功能实现
- spring boot配置shiro安全框架及用户登录权限验证实现
- 基于权限安全框架Shiro的登录验证功能实现
- 从零开始实现asp.net MVC4框架网站的用户登录以及权限验证模块 详细教程
- 使用AjaxPro框架实现无刷新用户登录验证【原创】
- Spring学习之SpringMVC框架快速搭建实现用户登录功能
- Spring学习之SpringMVC框架快速搭建实现用户登录功能
- 框架 day54 BOS项目练习(权限/角色/用户管理(CRUD),基于数据库实现动态授权,ehcache缓存权限,shiro标签,菜单权限展示)
- Java小程序之集合框架模拟数据库实现用户登录和注册功能
- Spring学习之SpringMVC框架快速搭建实现用户登录功能
- springMVC中实现用户登录权限验证
- Spring学习之SpringMVC框架快速搭建实现用户登录功能
- 使用AjaxPro框架实现无刷新用户登录验证【原创】