SpringBoot与Shiro整合-权限管理实战。
打开Eclipse,new Maven Project--Create a simple project
输入项目相关信息,Packing 选择为jar,点击Finish。
修改项目的编译环境为1.8
打开项目的pom.xml
<!-- 修改参数 --> <properties> <!-- 修改JDK的编译版本为1.8 --> <java.version>1.8</java.version> </properties>添加之后--右击项目-Maven-update Project
添加父级依赖
打开pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> </parent>添加项目依赖
打开pom.xml
<dependencies> <!-- 导入web支持 --> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>完整pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> </parent> <groupId>com.badao.springboot</groupId> <artifactId>springboot-shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- 导入web支持 --> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!-- 修改参数 --> <properties> <!-- 修改JDK的编译版本为1.8 --> <java.version>1.8</java.version> </properties> </project>在src/main/java下新建UserController
代码:
package com.badao.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { /*** * usercontroller测试 */ @RequestMapping("/hello") @ResponseBody public String hello() { System.out.println("**********************hello"); return "hello"; } }新建项目启动类Application.java,要与UserController同级
package com.badao; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * springboot启动类 * @author badao * @Description: * @Time:2019年5月19日 下午4:20:07 */ @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } }运行启动类
启动效果
打开浏览器访问
http://localhost:8080/hello
打开pom.xml
<!-- thymeleaf--> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>在src/main/resources下新建templates目录,目录下新建test.html
代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>Thymeleaf 使用</title> </head> <body> <h3 th:text="${username}"></h3> </body> </html>注意:
在thymeleaf3.0以前对页面标签语法要求比较严格开始标签必须有结束标签。
所以这里手动加上</meta>结束标签。
或者这里升级thymeleaf为3.0或更高。
具体参照:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/90344773
在UserController中新建测试方法
/*** * Thymeleaf测试 */ @RequestMapping("/testThymeleaf") public String testThymeleaf(Model model) { model.addAttribute("username","badao"); return "test"; }运行效果
启动启动类,打开浏览器输入:
http://localhost:8080/testThymeleaf
新建包shiro,包下新建UserRealm.java
package com.badao.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /*** * 自定义Realm * @author Administrator * @Description: * @Time:2019年5月19日 下午6:34:50 */ public class UserRealm extends AuthorizingRealm{ /*** * 执行授权逻辑 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub System.out.println("执行授权逻辑"); return null; } /*** * 执行认证逻辑 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // TODO Auto-generated method stub System.out.println("执行认证逻辑"); return null; } }shiro包下新建ShiroConfig.java配置类
package com.badao.shiro; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /*** * Shiro配置类 * @author Administrator * @Description: * @Time:2019年5月19日 下午6:33:48 */ @Configuration public class ShiroConfig { /*** * 创建ShiroFilterFactoryBean * @return */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); return shiroFilterFactoryBean; } /*** * 创建DefaultWebSecurityManager * @return */ @Bean(name="securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联realm securityManager.setRealm(userRealm); return securityManager; } /*** * 创建Realm * @return */ @Bean(name="userRealm") public UserRealm getRealm() { return new UserRealm(); } }注:
通过@Bean(name="userRealm")实现添加到spring容器,然后通过@Qualifier("userRealm")去引用。
打开test.html,添加两个超链接。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>Thymeleaf 使用</title> </head> <body> <h3 th:text="${username}"></h3> <br> <a href="add">添加</a> <a href="update">更新</a> </body> </html>注:
进行页面的跳转时不能直接跳转到具体的页面,必须经过controller跳转。
templates下新建user目录,目录下新建add.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>添加用户</title> </head> <body> <h1>开始添加用户</h1> </body> </html>再新建update.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>编辑用户</title> </head> <body> <h1>开始编辑用户</h1> </body> </html>来到UserController中,添加跳转页面方法。
/*** * 跳转到add */ @RequestMapping("/add") public String add() { return "user/add"; } /*** * 跳转到update */ @RequestMapping("/update") public String update() { return "user/update"; }运行项目,打开浏览器输入:
http://localhost:8080/testThymeleaf
需求:
访问首页即testThymeleaf时不进行验证,访问添加和编辑时进行拦截跳转到登录页面。
template下新建login.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h1>请登录</h1> </body> </html>打开ShiroConfig配置文件
添加Shiro内置过滤器:
1.anon:无需认证可以访问。
2.authc:必须认证才可以 访问。
3.user:如果使用rememberMe的功能可以直接访问。
4.perms:该资源必须得到资源权限才可以访问。
5.role:该资源必须得到角色权限才可以访问。
在getShiroFilterFactoryBean中:
@Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); //添加Shiro内置过滤器 Map<String, String> filterMap = new LinkedHashMap<String, String>(); filterMap.put("/add", "authc"); filterMap.put("/update", "authc"); //上面两行可以用通配符来配置 //filterMap.put("/*", "authc"); //不拦截首页 filterMap.put("/testThymeleaf", "anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); //修改调整的登录页面 shiroFilterFactoryBean.setLoginUrl("/login"); return shiroFilterFactoryBean; }在UserController中添加登录跳转
/*** * 跳转到login */ @RequestMapping("/login") public String login() { return "login"; }启动项目,输入:
http://localhost:8080/testThymeleaf
效果
编写login.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h1>请登录</h1> <font color="red" th:text="${msg}"></font> <form action="dologin" method="post"> 用户名:<input type="text" name="name"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="提交"> </form> </body> </html>UserController中添加登录方法
/*** * login */ @RequestMapping("/dologin") public String dologin(String name,String password,Model model) { /*** * 使用Shiro编写认证操作 * */ //1.获取Subject Subject subject = SecurityUtils.getSubject(); //2.封装用户数据 UsernamePasswordToken token = new UsernamePasswordToken(name,password); //3.执行登录方法 try { //登录成功,没有异常代表登录成功 //login方法会来到UserRealm中的执行认证的方法 subject.login(token); return "redirect:/testThymeleaf"; }catch (UnknownAccountException e) { //登录失败:用户名不存在 model.addAttribute("msg","用户名不存在"); return "/login"; }catch (IncorrectCredentialsException e){ //登录失败:密码不正确 model.addAttribute("msg","密码不正确"); return "/login"; } }注:
1.subject.login(token)会自动找到自定义Realm中的执行认证的方法。
2.没有异常就是登录成功,出现UnknownAccountException 就是用户名不正确,出现IncorrectCredentialsException 就是密码不正确。
修改UserRealm
/*** * 执行认证逻辑 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken args) throws AuthenticationException { // TODO Auto-generated method stub System.out.println("执行认证逻辑"); //假设数据库用户名和密码 String name = "badao"; String password = "123"; //1.判断用户名 UsernamePasswordToken token = (UsernamePasswordToken) args; if(!token.getUsername().equals(name)){ //用户名不存在 //shiro底层会抛出UnknownAccountException return null; } //2.判断密码 //编写shiro判断逻辑 return new SimpleAuthenticationInfo("",password,""); }在配置文件中给登录放行
Map<String, String> filterMap = new LinkedHashMap<String, String>(); filterMap.put("/add", "authc"); filterMap.put("/update", "authc"); //上面两行可以用通配符来配置 //filterMap.put("/*", "authc"); //不拦截首页 filterMap.put("/testThymeleaf", "anon"); filterMap.put("/dologin", "anon");运行项目,打开浏览器输入:
http://localhost:8080/testThymeleaf
效果
打开pom.xml
<!-- 导入Mybatis相关依赖 --> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency>新建表Users
在src/main/resources下新建application.properties
名字与位置必须一致。
代码:
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/shirotest?useUnicode=true&characterEncoding=UTF-8&useSSL=false spring.datasource.username=root spring.datasource.password=123 #配置数据源 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #配置别名 mybatis.type-aliases-package=com.badao.entity新建entity包,包下新建User.java
package com.badao.entity; public class User { int id; String userName; String password; public int getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return userName; } public void setUsername(String username) { this.userName = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }新建mapper包,包下新建UserMapper接口
package com.badao.mapper; import com.badao.entity.User; public interface UserMapper { public User findByName(String name); }再在此包新新建UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.badao.mapper.UserMapper"> <select id="findByName" resultType="user" parameterType="String"> select * from users where userName =#{value} </select> </mapper>新建service包,包下新建UserService接口
package com.badao.service; import com.badao.entity.User; public interface UserService { public User findByName(String name); }再在此包下新建UserServiceImpl
package com.badao.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.badao.entity.User; import com.badao.mapper.UserMapper; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findByName(String name) { // TODO Auto-generated method stub return userMapper.findByName(name); } }打开UserController,添加如下登录方法。
/*** * 跳转到login */ @RequestMapping("/login") public String login() { return "login"; } /*** * login */ @RequestMapping("/dologin") public String dologin(String name,String password,Model model) { /*** * 使用Shiro编写认证操作 * */ //1.获取Subject Subject subject = SecurityUtils.getSubject(); //2.封装用户数据 UsernamePasswordToken token = new UsernamePasswordToken(name,password); //3.执行登录方法 try { //登录成功,没有异常代表登录成功 //login方法会来到UserRealm中的执行认证的方法 subject.login(token); return "redirect:/testThymeleaf"; }catch (UnknownAccountException e) { //登录失败:用户名不存在 model.addAttribute("msg","用户名不存在"); return "/login"; }catch (IncorrectCredentialsException e){ //登录失败:密码不正确 model.addAttribute("msg","密码不正确"); return "/login"; } }打开UserRealm.java,修改为:
/*** * 执行认证逻辑 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken args) throws AuthenticationException { // TODO Auto-generated method stub System.out.println("执行认证逻辑"); //假设数据库用户名和密码 /*String name = "badao"; String password = "123";*/ UsernamePasswordToken token = (UsernamePasswordToken) args; User user = userService.findByName(token.getUsername()); //1.判断用户名 if(user==null){ //用户名不存在 //shiro底层会抛出UnknownAccountException return null; } //2.判断密码 //编写shiro判断逻辑 return new SimpleAuthenticationInfo("",user.getPassword(),""); }打开ShiroConfig,放开登录页面
Map<String, String> filterMap = new LinkedHashMap<String, String>(); filterMap.put("/add", "authc"); filterMap.put("/update", "authc"); //上面两行可以用通配符来配置 //filterMap.put("/*", "authc"); //不拦截首页 filterMap.put("/testThymeleaf", "anon"); filterMap.put("/login", "anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);打开Application.java,添加@MapperScan("com.badao.mapper"):
@SpringBootApplication @MapperScan("com.badao.mapper") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } }打开ShiroConfig配置文件,添加授权过滤器。
//授权过滤器 //注意:当授权拦截后,shiro会自动跳转到未授权页面 filterMap.put("/add", "perms[user:add]");打开UserController,添加未授权页面跳转
/*** * 跳转到未授权页面 */ @RequestMapping("/login") public String login() { return "login"; }在templates下新建unAuth.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>没有授权</title> </head> <body> <h1>没有授权</h1> </body> </html>注意:
添加资源的授权字符串要与上面进行拦截的字符串一致才能跳过拦截。
效果:
为了简单的进行测试,不再建立角色表与权限表。
直接添加权限列。
授予badao用户 user:add权限
授予liumang用户 user:update权限
打开Shiroconfig.java
//注意:当授权拦截后,shiro会自动跳转到未授权页面 filterMap.put("/add", "perms[user:add]"); filterMap.put("/update", "perms[user:update]");打开UserRealm.java
/*** * 执行授权逻辑 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub System.out.println("执行授权逻辑"); //给资源进行授权 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //添加资源的授权字符串 //info.addStringPermission("user:add"); //获取当前登录用户 Subject subject = SecurityUtils.getSubject(); User user = (User)subject.getPrincipal(); userService.findById(user.getId()); info.addStringPermission(user.getPerms()); return info; }注:
User user = (User)subject.getPrincipal();这句中的getPrincipal()就是获取下面执行逻辑认证的
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
第一个参数。
打开pom.xml
<dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>打开ShiroConfig
/*** * 配置ShiroDialect 用于thymeleaf和Shiro便签配合使用 */ @Bean public ShiroDialect getShiroDialect() { return new ShiroDialect(); }打开test.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>Thymeleaf 使用</title> </head> <body> <h3 th:text="${username}"></h3> <br> <div shiro:hasPermission="user:add"> <a href="add">添加</a> </div> <div shiro:hasPermission="user:update"> <a href="update">更新</a> </div> <br> <a href="login">登录</a> </body> </html>
https://download.csdn.net/download/badao_liumang_qizhi/11194439
