SpringBoot之Shiro整合登陆验证、角色验证和权限验证

论坛 期权论坛 脚本     
匿名技术用户   2020-12-21 19:53   23   0

首先要感谢这篇文章的博主,参考文章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

每天都有一个小目标,让自己不在那么迷茫

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP