shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/ 它提供了很方便的权限认证和登录的功能.
而springboot作为一个开源框架,必然提供了和shiro整合的功能!接下来就用springboot结合springmvc,mybatis,整合shiro完成对于用户登录的判定和权限的验证.
1.准备数据库表结构
这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表(角色和权限是多对多的).表结构建立的sql语句如下:
CREATE TABLE `module` ( `mid` int(11) NOT NULL AUTO_INCREMENT, `mname` varchar(255) DEFAULT NULL, PRIMARY KEY (`mid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of module -- ---------------------------- INSERT INTO `module` VALUES (‘1‘, ‘add‘); INSERT INTO `module` VALUES (‘2‘, ‘delete‘); INSERT INTO `module` VALUES (‘3‘, ‘query‘); INSERT INTO `module` VALUES (‘4‘, ‘update‘); -- ---------------------------- -- Table structure for module_role -- ---------------------------- DROP TABLE IF EXISTS `module_role`; CREATE TABLE `module_role` ( `rid` int(11) DEFAULT NULL, `mid` int(11) DEFAULT NULL, KEY `rid` (`rid`), KEY `mid` (`mid`), CONSTRAINT `mid` FOREIGN KEY (`mid`) REFERENCES `module` (`mid`), CONSTRAINT `rid` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of module_role -- ---------------------------- INSERT INTO `module_role` VALUES (‘1‘, ‘1‘); INSERT INTO `module_role` VALUES (‘1‘, ‘2‘); INSERT INTO `module_role` VALUES (‘1‘, ‘3‘); INSERT INTO `module_role` VALUES (‘1‘, ‘4‘); INSERT INTO `module_role` VALUES (‘2‘, ‘1‘); INSERT INTO `module_role` VALUES (‘2‘, ‘3‘); -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `rid` int(11) NOT NULL AUTO_INCREMENT, `rname` varchar(255) DEFAULT NULL, PRIMARY KEY (`rid`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of role -- ---------------------------- INSERT INTO `role` VALUES (‘1‘, ‘admin‘); INSERT INTO `role` VALUES (‘2‘, ‘customer‘); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (‘1‘, ‘hlhdidi‘, ‘123‘); INSERT INTO `user` VALUES (‘2‘, ‘xyycici‘, ‘1992‘); -- ---------------------------- -- Table structure for user_role -- ---------------------------- DROP TABLE IF EXISTS `user_role`; CREATE TABLE `user_role` ( `uid` int(11) DEFAULT NULL, `rid` int(11) DEFAULT NULL, KEY `u_fk` (`uid`), KEY `r_fk` (`rid`), CONSTRAINT `r_fk` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`), CONSTRAINT `u_fk` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user_role -- ---------------------------- INSERT INTO `user_role` VALUES (‘1‘, ‘1‘); INSERT INTO `user_role` VALUES (‘2‘, ‘2‘);
2.建立Maven工程,建立实体类,搭建mybatis开发环境
maven工程的基本目录如下:
为了方便,直接在父工程中,导入全部的依赖:
<!-- springboot的启动所需配置.包括自动配置,封装jar包等等 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.0.RELEASE</version> </parent> <properties> <java.version>1.7</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <scope>true</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.18</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.18</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!-- shiro spring. --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.2</version> </dependency> <!-- shiro ehcache --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.2</version> </dependency> <!-- 包含支持UI模版(Velocity,FreeMarker,JasperReports), 邮件服务, 脚本服务(JRuby), 缓存Cache(EHCache), 任务计划Scheduling(uartz)。 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- servlet 依赖. --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!-- tomcat 的支持.--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <configuration> <!--fork : 如果没有该项配置则devtools不会起作用,即应用不会restart --> <fork>true</fork> </configuration> </plugin> </plugins> </build> <modules> <module>spring-boot-shiro-dao</module> <module>spring-boot-shiro-service</module> <module>spring-boot-shiro-web</module> </modules>
可以看出这里采用的是阿里巴巴的Druid数据库.在spring-boot-shiro-web下建立application.properties文件.它主要配置对于数据库信息和jsp的支持:
##tomcat## server.tomcat.uri-encoding=UTF-8 ##Druid## spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=root spring.datasource.initialSize=5 spring.datasource.minIdle=5 spring.datasource.maxActive=20 spring.datasource.maxWait=60000 spring.datasource.timeBetweenEvictionRunsMillis=60000 spring.datasource.minEvictableIdleTimeMillis=300000 spring.datasource.validationQuery=SELECT 1 FROM DUAL spring.datasource.testWhileIdle=true spring.datasource.testOnBorrow=false spring.datasource.testOnReturn=false spring.datasource.poolPreparedStatements=true spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 spring.datasource.filters=stat,wall,log4j spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 spring.datasource.useGlobalDataSourceStat=true ##jsp## spring.mvc.view.prefix=/jsp/ spring.mvc.view.suffix=.jsp
在spring-boot-shiro-web下建立数据库连接池的配置类完成对于数据库连接池的配置:
/** * 数据库连接池&Mybatis配置类 * @author Administrator * */ @Configuration public class DruidConfiguation { @Bean public ServletRegistrationBean statViewServle(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*"); //白名单: servletRegistrationBean.addInitParameter("allow","192.168.1.218,127.0.0.1"); //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的即提示:Sorry, you are not permitted to view this page. servletRegistrationBean.addInitParameter("deny","192.168.1.100"); //登录查看信息的账号密码. servletRegistrationBean.addInitParameter("loginUsername","druid"); servletRegistrationBean.addInitParameter("loginPassword","12345678"); //是否能够重置数据. servletRegistrationBean.addInitParameter("resetEnable","false"); return servletRegistrationBean; } @Bean public FilterRegistrationBean statFilter(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); //添加过滤规则. filterRegistrationBean.addUrlPatterns("/*"); //添加不需要忽略的格式信息. filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean; } @Bean PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){ return new PersistenceExceptionTranslationPostProcessor(); } //配置数据库的基本链接信息 @Bean(name = "dataSource") @Primary @ConfigurationProperties(prefix = "spring.datasource") //可以在application.properties中直接导入 public DataSource dataSource(){ return DataSourceBuilder.create().type(com.alibaba.druid.pool.DruidDataSource.class).build(); } @Bean public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) { SqlSessionFactoryBean bean=new SqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean; } }
接着在spring-boot-shiro-web下建立Application类:
@SpringBootApplication @EnableTransactionManagement @MapperScan("com.xyy.springboot.shiro.mapper")//配置mybatis包扫描 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
紧接着,我们根据数据库的表结构在spring-boot-shiro-dao的项目下建立实体类User,Role,Module.它们的意义在上文中已经说明了:
接着就可以书写mapper了,注意,mapper所在的位置需要和Application类中配置的包扫描的位置保持一致,我们的需求是根据用户名在数据库中查询出指定的用户表的记录,与此同时查询出对应的角色以及角色所对应的权限,并且封装到实体类User中.UserMapper接口如下:
UserMapper.xml如下:
<mapper namespace="com.xyy.springboot.shiro.mapper.UserMapper"> <resultMap type="com.xyy.springboot.shiro.pojo.User" id="userMap"> <id property="uid" column="uid"/> <result property="username" column="username"/> <result property="password" column="password"/> <collection property="roles" ofType="com.xyy.springboot.shiro.pojo.Role"> <id property="rid" column="rid"/> <result property="rname" column="rname"/> <collection property="modules" ofType="com.xyy.springboot.shiro.pojo.Module"> <id property="mid" column="mid"/> <result property="mname" column="mname"/> </collection> </collection> </resultMap> <select id="findByUserName" parameterType="string" resultMap="userMap"> SELECT u.*,r.*,m.* FROM user u inner join user_role ur on ur.uid=u.uid inner join role r on r.rid=ur.rid inner join module_role mr on mr.rid=r.rid inner join module m on mr.mid=m.mid WHERE username=#{username}; </select> </mapper>
在spring-boot-shiro-service建立UserService和UserServiceImpl,完成业务层对于mapper的调用: