【what】
1、定义:
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
2、核心组件:
(1)Subject:
即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
 Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
(2)SecurityManager:
它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
(3) Realm:
Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
 从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
demo实例
1、全文的配置文件pom.xml
<groupId>com.wangbin</groupId>
<artifactId>hello-spring-boot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>hello-spring-boot-shiro</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.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</artifactId>
</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-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</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.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2、整体代码风格:

3、登录校验
(1)ShiroConfig类
package com.wangbin.hello.spring.boot.shiro.shiro;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.DefaultSecurityManager;
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;
import java.util.LinkedHashMap;
import java.util.Map;
/
 shiro配置类
/
@Configuration
public class ShiroConfig {
   /
     创建ShiroFilterFactoryBean
    /
   @Bean
   public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier(“SecurityManager”) DefaultSecurityManager SecurityManager) {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       //设置安全管理器
       shiroFilterFactoryBean.setSecurityManager(SecurityManager);
       //shiro内置过滤器 用来拦截资源
       //常用过滤器
       /
         anon 无需认证(登陆) 可以访问
         authc 必须认证才可以访问
         user: 如果使用remeberme的功能可以直接访问
         role: 改资源必须得到角色的权限才能访问
         perms:该资源必须得到资源权限才可以访问
        /
       Map
//        map.put(“/add”,”authc”);
//        map.put(“/update”,”authc”);
       ///拦截user下的所有请求
       map.put(“/testThymeleaf”,”anon”);
       map.put(“/login”,”anon”);
       //资源授权过滤器
       map.put(“/add”,”perms[user:add]”);
       map.put(“/update”,”perms[user:update]”);
       map.put(“/*”,”authc”);
       //设置未登录跳转页面
       shiroFilterFactoryBean.setLoginUrl(“/tologin”);
       //设置未授权跳转页面
       shiroFilterFactoryBean.setUnauthorizedUrl(“/noAuth”);
       shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
       return shiroFilterFactoryBean;
   }
   /
     创建DefaultWebSecurityManger
    /
   @Bean(name = “SecurityManager”)
   public DefaultWebSecurityManager getDefaultSecurityManager(@Qualifier(“userRealm”) UserRealm userRealm){
       DefaultWebSecurityManager SecurityManager = new DefaultWebSecurityManager();
       //需要关联Realm
       SecurityManager.setRealm(userRealm);
       return SecurityManager;
   }
   /
     创建Realm
    /
   @Bean(name = “userRealm”)
   public UserRealm getRealm(){
       return new UserRealm();
   }
   /*
     配置ShiroDialect,用于thymeleaf和shiro标签配合使用
    /
   @Bean
   public ShiroDialect getShiroDialect(){
       return new ShiroDialect();
   }
}
(2)userRealm类
package com.wangbin.hello.spring.boot.shiro.shiro;
import com.wangbin.hello.spring.boot.shiro.entity.User;
import com.wangbin.hello.spring.boot.shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
/**
 自定义realm
/
public class UserRealm extends AuthorizingRealm {
   @Autowired
   private UserService userService;
   /**
     授权
     @param principalCollection
     @return
    /
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       System.out.println(“走授权”);
       SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
       Subject subject = SecurityUtils.getSubject();
       User user = (User) subject.getPrincipal();
       User dbuser = userService.findeById(user.getId());
       info.addStringPermission(dbuser.getPerms());
       //添加授权字符串
//        info.addStringPermission(“user:add”);
       return info;
   }
   /**
     认证逻辑
     @param authenticationToken
     @return
     @throws AuthenticationException
    /
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       System.out.println(“走认证”);
       //从前面传过来的toke
       UsernamePasswordToken token =(UsernamePasswordToken) authenticationToken;
       //获得用户名
       User user = userService.findeByName(token.getUsername());
       System.out.println(“这一步”);
       //判断用户名
    if(user==null){
        //用户名不存在
        return null;
       }
       //判断密码
       return  new SimpleAuthenticationInfo(user,user.getPassword(),””);
   }
}
(3)UserController类
package com.wangbin.hello.spring.boot.shiro.controller;
import com.wangbin.hello.spring.boot.shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
public class UserController {
   /
     测试spring-boot
    
     @return
    /
   @RequestMapping(“/hello”)
   @ResponseBody
   public String hello() {
       System.out.println(“hello,spring-boot”);
       return “ok”;
   }
   @RequestMapping(“testThymeleaf”)
   public String testThymeleaf(Model model) {
       model.addAttribute(“message”, “hello-spring-boot-shiro”);
       return “test”;
   }
   @RequestMapping(“/add”)
   public String add() {
       return “/user/add”;
   }
   @RequestMapping(“/noAuth”)
   public String noAuth(){
       return “noAuth”;
   }
   @RequestMapping(“/update”)
   public String update() {
       return “/user/update”;
   }
   @RequestMapping(value = “/tologin”)
   public String tologin(@ModelAttribute(“message”) String message,Model model) {
       model.addAttribute(“message”,message);
       return “/login”;
   }
   @RequestMapping(value = “login” ,method = RequestMethod.POST)
   public String login(String name, String password, Model model, RedirectAttributes redirectAttributes) {
       /
         shiro进行认证操作
        /
       //获得Subject
       Subject subject = SecurityUtils.getSubject();
       //封装用户数据
       UsernamePasswordToken token = new UsernamePasswordToken(name, password);
       //执行登陆方法
       try {
           subject.login(token);
           return “redirect:/testThymeleaf”;
           //登陆成功
       } catch (UnknownAccountException e) {
           //登陆失败并且表示用户名不存在
       redirectAttributes.addFlashAttribute(“message”, “用户名不存在”);
       return “redirect:/tologin”;
       } catch (IncorrectCredentialsException e) {
       //登陆失败并且表示密码错误
       redirectAttributes.addFlashAttribute(“message”, “用户密码错误”);
       return “redirect:/tologin”;
       }
   }
}
(4)User类 实体类
package com.wangbin.hello.spring.boot.shiro.entity;
public class User {
   private String name;
   private String password;
   private int id;
   private String perms;
   public String getPerms() {
       return perms;
   }
   public void setPerms(String perms) {
       this.perms = perms;
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
   public String getPassword() {
       return password;
   }
   public void setPassword(String password) {
       this.password = password;
   }
   public int getId() {
       return id;
   }
   public void setId(int id) {
       this.id = id;
   }
   @Override
   public String toString() {
       return “User{“ +
               “name=’” + name + ‘\’’ +
               “, password=’” + password + ‘\’’ +
               “, id=” + id +
               ‘}’;
   }
}
(5)service类
package com.wangbin.hello.spring.boot.shiro.service;
import com.wangbin.hello.spring.boot.shiro.entity.User;
public interface UserService {
   User findeByName(String name);
   User findeById(int id);
}
(6)serviceimpl类
package com.wangbin.hello.spring.boot.shiro.service.Impl;
import com.wangbin.hello.spring.boot.shiro.entity.User;
import com.wangbin.hello.spring.boot.shiro.mapper.UserMapper;
import com.wangbin.hello.spring.boot.shiro.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
   @Autowired
   private UserMapper userMapper;
   @Override
   public User findeByName(String name) {
       User user = userMapper.findByName(name);
       System.out.println(user.toString());
       return user;
   }
   @Override
   public User findeById(int id) {
       return userMapper.findById(id);
   }
}
(7)Usermapper类
package com.wangbin.hello.spring.boot.shiro.mapper;
import com.wangbin.hello.spring.boot.shiro.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper {
   User findByName(String name);
   User findById(int id);
}
(8)UserMapper.xml
package com.wangbin.hello.spring.boot.shiro.mapper;
import com.wangbin.hello.spring.boot.shiro.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper {
   User findByName(String name);
   User findById(int id);
}
(9)Application.yml配置文件
spring:
 datasource:
   druid:
     url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
     username: root
     password: 123456
     initial-size: 1
     min-idle: 1
     max-active: 20
     test-on-borrow: true
     driver-class-name: com.mysql.jdbc.Driver
mybatis:
 type-aliases-package: com.wangbin.hello.spring.boot.shiro.entity
 mapper-locations: classpath:mapper//.xml
 
                         
                                

