SpringBoot之Shiro整合登陆验证、角色验证和权限验证
首先要感谢这篇文章的博主,参考文章http://www.ityouknow.com/springboot/2017/06/26/springboot-shiro.html
以下就要开始我的表演啦(我还是一个菜鸟,大佬请绕道)
这一次我是用SpringBoot搭建,推荐大家学习Shiro的时候,从开始的shiro.ini配置文件开始学习起,废话不多说,先看数据表结构。
再看看我的pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.xiaobin</groupId>
<artifactId>SpringbootShiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringbootShiro</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这里的模版是用的thymeleaf,需要在src/main/resources/templates创建六个页面,如下图:
页面内容很简单,都是一些文字提示,没有具体的操作内容,除了login.html有一个form提交表单。
再来看看我的application.yml配置文件
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password:
thymeleaf:
cache: false
mode: LEGACYHTML5
mybatis:
mapper-locations: classpath:mapper/*.xml
在然后就是dao层和service层的东西就贴个图吧(嘻嘻,偷懒)
配置shiro的重中之重来啦,打起精神。
首先需要自己配置一个集成org.apache.shiro.realm.AuthorizingRealm类,主要是来验证登陆和权限
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserDaoService userDaoService;
@Autowired
private RoleDaoService roleDaoService;
@Autowired
private PermissionDaoService permissionDaoService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 能进入到这里,表示账号已经通过验证了
String username = (String) principals.getPrimaryPrincipal();
User user = userDaoService.selectByNameUser(username);
//先把所拥有的角色给获取
Set<String> roleString = roleDaoService.selectByUserIdString(user.getUserId());
//查询该用户所拥有的角色
List<Role> roleList = roleDaoService.selectByUserIdRoles(user.getUserId());
//查询所有角色所拥有的权限
Set<String> perms = new HashSet<>();
for(Role role : roleList) {
Set<String> permString = permissionDaoService.selectByRoleIdPermissionString(role.getRoleId());
perms.addAll(permString);
}
// 授权对象
SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
// 把通过DAO获取到的角色和权限放进去
s.setStringPermissions(perms);
s.setRoles(roleString);
return s;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
//获取登陆的用户名和密码
UsernamePasswordToken t = (UsernamePasswordToken) token;
String username = token.getPrincipal().toString();
String password = new String(t.getPassword());
//从数据库中获取登陆的用户
User user = userDaoService.selectByNameUser(username);
if(null==user) {
System.out.println("没找到此用户");
throw new AuthenticationException();
}
//把用户输入的密码进行md5和盐加密一起运算两次
String encodedPassword = new SimpleHash("md5", password, user.getSalt(), 2).toString();
if (!user.getPassword().equals(encodedPassword)) {
System.out.println("密码错误");
throw new AuthenticationException();
}
// 认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(username, password, getName());
return a;
}
}
然后再试shiro的全局配置啦,Apache Shiro 核心通过 Filter 来实现
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/index", "anon");
// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
//这里可以手动加入角色和权限
// filterChainDefinitionMap.put("/userinfo","roles[admin],perms[userList]");
// filterChainDefinitionMap.put("/userAdd","roles[userManger]");
filterChainDefinitionMap.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//没有授权就会跳转到403.html 这里我的好像没有效,我用的是MyException来捕捉没有权限的异常
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//自定义Realm拦截处理,这个类很重要
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/**
* 开启aop注解支持
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
shiro配置基本就完结啦现在我们添加Controller来测试一下
@Controller
public class IndexController {
@RequestMapping({"/","/index"})
public String index() {
return "index";
}
/**
* 页面login.html中form表单action的提交地址
* 不处理登陆验证,假如还是跳转到/login.html就是用户或者密码错误
* @param map
* @return
*/
@RequestMapping("login")
public String login(){
return "login";
}
/**
* 没有权限就会跳转到403.html
* @return
*/
@RequestMapping("/403")
public String unauthorizedRole() {
return "403";
}
}
还有一个Controller是对其它三个页面的跳转,主要是使用@RequiresRoles和@RequiresPermissions两个注解
@Controller
public class UserController {
/**
* 访问用户列表页面
* @return
*/
@RequestMapping("/userlist")
@RequiresPermissions("userList")//我的用户并没有userList这个权限,所以访问不了
public String userlist() {
return "userInfo";
}
/**
* 访问用户增加页面
* @return
*/
@RequestMapping("/useradd")
@RequiresRoles("admin")//我的用户并没有admin这个角色,所以访问不了
public String useradd() {
return "userAdd";
}
/**
* 访问用户删除页面
* @return
*/
@RequestMapping("/userdelete")
public String userdelete() {
return "userDelete";
}
}
结果图
码云地址:https://gitee.com/MyXiaoXiaoBin/SpringBootShiro
每天都有一个小目标,让自己不在那么迷茫