前面简单介绍了shiro这个框架的一些基本知识,包括其架构模型,主要的功能,关键名称的含义,以及核心模块和对应的接口定义。
今天我们从一个简单示例,先了解使用shiro实现Web应用认证时,一名开发者需要做些什么。同样秉持着技术学习的原则,我们仅仅使用shiro框架以及一些其他简化开发的工具库,不会涉及到一些IOC容器,这样在进行模块配置以及依赖关系梳理时,通过手动的配置的方式,让我们更加容易理解...
通过这篇文章,你可以有以下几个方面的收获:
1) 你可以选择通过你的IDE快速创建一个项目,比如通过Intellij Idea,通过File->New->Project选择Maven Archetype创建一个空项目,这里archetype可以选择quickstart
这里你很可能遇到一个idea的bug,按上图提交后,发现idea卡死了,项目创建失败且无法打开,如果没有就恭喜你了
2)最终我们会得到一个文件夹,里面包含一个pom.xml文件,结构如下(如果有其他的内容建议删除,比如src,因为这个pom我们作为项目parent维护)
细心的你会注意到,在根目录下有个pom.xml,同时还有个ui-mvc目录下也有个pom.xml文件,根目录下的我一般习惯作为整个项目的父级依赖配置文件,用来管理所有依赖、插件版本以及属性值,ui-mvc下的pom主要通过parent实现属性继承,这样来实现配置集中化管理
./pom.xml
< project >
//...
< groupId >com.sucls.security< /groupId >
< artifactId >auth-shiro< /artifactId >
< version >1.0-SNAPSHOT< /version >
< packaging >pom< /packaging >
< properties >
< project.build.sourceEncoding >UTF-8< /project.build.sourceEncoding >
< maven.compiler.source >1.8< /maven.compiler.source >
< maven.compiler.target >1.8< /maven.compiler.target >
< shiro.version >1.9.1< /shiro.version >
// ...
< /properties >
< dependencyManagement >
< dependencies >
< !-- 核心 -- >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-core< /artifactId >
< version >${shiro.version}< /version >
< /dependency >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-web< /artifactId >
< version >${shiro.version}< /version >
< /dependency >
// ...
< /dependencies >
< /dependencyManagement >
// ...
< /project >
./ui-mvc/pom.xml
< parent >
< groupId >com.sucls.security< /groupId >
< artifactId >auth-shiro< /artifactId >
< version >1.0-SNAPSHOT< /version >
< relativePath >../../pom.xml< /relativePath >
< /parent >
< artifactId >auth-shiro-ui-mvc< /artifactId >
< packaging >war< /packaging >
< name >ui-mvc< /name >
< dependencies >
< !-- 核心 -- >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-core< /artifactId >
< /dependency >
< dependency >
< groupId >org.apache.shiro< /groupId >
< artifactId >shiro-web< /artifactId >
< /dependency >
< /dependencies >
大部分内容都省略了,可以参考文末源代码,主要引入了shiro相关的依赖,以及一个提高开发效率的工具包
我们所有代码都会写到ui-mvc模块下,看到名称就知道我们通过mvc的结构,因此前端是通过jsp这个老技术,后面会讲到如何通过前后端分离来实现认证功能。
下面主要从以下几个方面进行配置:
web.xml以前说过,认证基本都是基于Filter实现,同样shiro有一个核心的过滤器(该过滤器会将我们的配置解析成一个个过滤器链)
< filter >
< filter-name >shiroFilter< /filter-name >
< filter-class >org.apache.shiro.web.servlet.ShiroFilter< /filter-class >
< /filter >
< filter-mapping >
< filter-name >shiroFilter< /filter-name >
< url-pattern >/*< /url-pattern >
< /filter-mapping >
配置监听,在系统启动时基于ServletContextListener调用初始化参数完成一些基本的系统初始化工作
< context-param >
< param-name >shiroEnvironmentClass< /param-name >
< param-value >org.apache.shiro.web.env.DefaultWebEnvironment< /param-value >
< /context-param >
< listener >
< listener-class >com.sucls.security.security.SimpleEnvironmentLoaderListener< /listener-class >
< /listener >
这里通过自定义的监听,SimpleEnvironmentLoaderListener类承载了shiro基本上所有的配置,在这里我们会完整地构建SecurityManager对象以及Filter的配置,如果读过以前的文章你就会知道,SecurityManager主要的工作包括:
ShiroFilter配置
FormAuthenticationFilter authcFilter = (FormAuthenticationFilter) filterChainResolver.getFilterChainManager().getFilters().get(DefaultFilter.authc.name());
authcFilter.setLoginUrl("/login.jsp");
authcFilter.setSuccessUrl("/index.html");
filterChainResolver.getFilterChainManager().addToChain("/webjars/**", DefaultFilter.anon.name());
filterChainResolver.getFilterChainManager().addToChain("/assets/**", DefaultFilter.anon.name());
filterChainResolver.getFilterChainManager().addToChain("/**", DefaultFilter.authc.name());
这里主要通过配置FilterChainResolver对象来完成ShiroFilter对象的构建,后面讲到源代码时会细说。
SecurityManager配置
private void configureWebSecurityManager(DefaultWebSecurityManager securityManager) {
//
securityManager.setAuthenticator(newAuthenticator());
securityManager.setRealms(Arrays.asList(initRealm()));
}
private Authenticator newAuthenticator() {
ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); // 至少一个Realm
authenticator.setRealms(Arrays.asList(initRealm()) );
return authenticator;
}
private Realm initRealm(){
return RealmBuilder.create()
.inMemoryRealm() .user("admin").password("123456").role("ROLE_ADMIN").permissions(Arrays.asList("read","edit","create","delete"))
.and()
.user("user").password("123456").role("ROLE_USER").permission("read")
.build();
}
这里仅根据需要配置了Realm以及认证规则Authenticator
前端模板来源bootstrap quick,在此基础上修改了远程资源(js、css)为本地引用,以及引入jsp文件头对应的配置
通过引入tomcat插件来启动项目:
< plugin >
< groupId >org.apache.tomcat.maven< /groupId >
< artifactId >tomcat7-maven-plugin< /artifactId >
< version >2.2< /version >
< configuration >
< port >8080< /port >
< path >/< /path >
< /configuration >
< /plugin >
这样不需要我们单独弄个tomcat,通过插件即可实现项目热启动,方便调试与静态页面的修改
1)进入系统 http://localhost:8080/ 由于没有登录,跳转到登录页http://localhost:8080/login.jsp
2)输入用户名密码,按以上的配置admin/123456,登录成功,进入主页
3)用户鉴权,上面可以看到admin配置了ROLE_ADMIN角色,user配置了ROLE_USER角色,所以
admin登录时:
访问 http://localhost:8080/system/getProperties.json 正常返回数据 ;
访问 http://localhost:8080/subject/getSubject.json 进入未授权页面
关于shiro鉴权部分主要是基于Filter以及AOP完成,其中请求交易基于Filter,在请求时基于登录权限信息进行交易拦截,而AOP则可以针对方法的调用阶段,更加灵活和通用。具体的实现过程后面会细说,同时可以看到示例简单的实现过程
在整个示例中,回忆我们做了什么,有什么用?
/assets/** = anon
/login = authc
/admin/** = roles[ROLE_ADMIN]
/admin/add* = perms[add:*] //[action:type:instance]
/** = authc
要知道,我们的目的是为SecurityManager注入属性以及配置ShiroFilter过滤规则,并不一定需要基于ServletContextListener,这只是一个选择,比如还可以在Filter的init方法中完成,只要保证系统启动后对应的配置加载或处理完成即可。
全部0条评论
快来发表一下你的评论吧 !