【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

  1. <groupId>com.wangbin</groupId>
  2. <artifactId>hello-spring-boot-shiro</artifactId>
  3. <version>0.0.1-SNAPSHOT</version>
  4. <packaging>jar</packaging>
  5. <name>hello-spring-boot-shiro</name>
  6. <description>Demo project for Spring Boot</description>
  7. <parent>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-parent</artifactId>
  10. <version>2.1.1.RELEASE</version>
  11. <relativePath/> <!-- lookup parent from repository -->
  12. </parent>
  13. <properties>
  14. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  15. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  16. <java.version>1.8</java.version>
  17. </properties>
  18. <dependencies>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-test</artifactId>
  26. <scope>test</scope>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  36. <version>2.0.4.RELEASE</version>
  37. </dependency>
  38. <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
  39. <dependency>
  40. <groupId>org.apache.shiro</groupId>
  41. <artifactId>shiro-spring</artifactId>
  42. <version>1.4.0</version>
  43. </dependency>
  44. <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
  45. <dependency>
  46. <groupId>com.alibaba</groupId>
  47. <artifactId>druid-spring-boot-starter</artifactId>
  48. <version>1.1.10</version>
  49. </dependency>
  50. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  51. <dependency>
  52. <groupId>mysql</groupId>
  53. <artifactId>mysql-connector-java</artifactId>
  54. <version>5.1.32</version>
  55. </dependency>
  56. <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
  57. <dependency>
  58. <groupId>org.mybatis.spring.boot</groupId>
  59. <artifactId>mybatis-spring-boot-starter</artifactId>
  60. <version>1.3.2</version>
  61. </dependency>
  62. <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
  63. <dependency>
  64. <groupId>com.github.theborakompanioni</groupId>
  65. <artifactId>thymeleaf-extras-shiro</artifactId>
  66. <version>2.0.0</version>
  67. </dependency>
  68. </dependencies>
  69. <build>
  70. <plugins>
  71. <plugin>
  72. <groupId>org.springframework.boot</groupId>
  73. <artifactId>spring-boot-maven-plugin</artifactId>
  74. </plugin>
  75. </plugins>
  76. </build>

2、整体代码风格:

Shiro - 图1

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 =new LinkedHashMap();
// 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