浅谈Shiro安全框架

Shiro

    • 一,什么是Shiro
    • 二,Shiro核心组件
    • 三,Shiro的运行机制图
    • 四,Shiro的认证和授权规则
    • 五,SpringBoot整合Shiro
      • 使用Shiro做权限管理
          • 1,数据库
          • 2,创建springboot项目,导入依赖
          • 3,编写yml文件
          • 4,编写实体类
          • 5,编写dao
          • 6,编写service及实现类
          • 7,编写realm类
          • 8,编写config类
          • 9,编写controller类
          • 10,页面
          • 测试结果
          • 代码下载地址

一,什么是Shiro

官网
Shiro是一款主流的java安全框架,不依赖任何容器可以运行在javase和javaee项目中,它的主要作用
是访问系统的用户进行身份认证,授权,会话管理,加密等操作
Shiro就是用来解决安全管理的系统化框架

二,Shiro核心组件

  • UsernamePasswordToken:Shiro用来封装用户登录信息,使用用户的登录信息来创建令牌Token
  • SecurityManager:Shiro的核心部分,负责安全认证和授权
  • Suject:Shiro的一个抽象概念,包含了用户信息
  • Realm:开发者自定义的模板,根据项目的需求验证和授权的逻辑全部写在Realm中
  • AuthenticationInfo:用户的角色信息集合,认证时使用
  • AuthorzationInfo:角色的权限信息集合,授权时使用
  • DefaultWebSecurityManager:安全管理器,开发者自定义的Realm需要注入到DefaultWebSecurityManager进行管理才能生效
  • ShiroFIlterFactoryBean:过滤器工作,Shiro的基本运行机制是开发者定制规则,Shiro去执行,具体的执行操作就是由ShiroFIlterFactoryBean窗机 的一个个Filter对象来完成的

三,Shiro的运行机制图

浅谈Shiro安全框架_第1张图片

四,Shiro的认证和授权规则

  • 认证过滤器
    • anon:无需认证
    • authc:必须认证
    • authcBasic:需要通过HttpBasic认证
    • user:不一定通过认证,只需要曾经被Shiro记录即可
  • 授权过滤器
    • Perms:必须拥有某个权限才能访问
    • role:必须拥有某个角色才能访问
    • port:请求的端口必须是指定值才可以
    • rest:请求必须基于RestFul风格
    • ssl:必须是安全的url请求,协议HTTPS

五,SpringBoot整合Shiro

使用Shiro做权限管理

1,数据库
-- MySQL dump 10.13  Distrib 8.0.19, for Win64 (x86_64)
--
-- Host: 127.0.0.1    Database: test
-- ------------------------------------------------------
-- Server version	8.0.19

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `account`
--

DROP TABLE IF EXISTS `account`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `account` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  `perms` varchar(20) DEFAULT NULL,
  `role` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `account`
--

LOCK TABLES `account` WRITE;
/*!40000 ALTER TABLE `account` DISABLE KEYS */;
INSERT INTO `account` VALUES (1,'zs','123123','',''),(2,'ls','123123','manage','administrator'),(3,'ww','123123','','');
/*!40000 ALTER TABLE `account` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2020-06-04 14:10:15
2,创建springboot项目,导入依赖
<?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 https://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>2.1.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.bd13</groupId>
    <artifactId>springboot-shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-shiro</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--shiro依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>
        <!--Shiro 整合 Thymeleaf 依赖-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
3,编写yml文件
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 09301225
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4,编写实体类
package com.bd13.springbootshiro.entity;

public class Account {
     
    private Integer id;
    private String username;
    private String password;
    private String perms;
    private String role;

    public Integer 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;
    }

    public String getPerms() {
     
        return perms;
    }

    public void setPerms(String perms) {
     
        this.perms = perms;
    }

    public String getRole() {
     
        return role;
    }

    public void setRole(String role) {
     
        this.role = role;
    }
}
5,编写dao
package com.bd13.springbootshiro.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bd13.springbootshiro.entity.Account;

public interface AccountMapper extends BaseMapper<Account> {
     
}
6,编写service及实现类
package com.bd13.springbootshiro.service;

import com.bd13.springbootshiro.entity.Account;

public interface AccountService {
     
    public Account findByUsername(String username);
}
package com.bd13.springbootshiro.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bd13.springbootshiro.entity.Account;
import com.bd13.springbootshiro.mapper.AccountMapper;
import com.bd13.springbootshiro.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountServiceImpl implements AccountService {
     
    @Autowired
    private AccountMapper accountMapper;
    @Override
    public Account findByUsername(String username) {
     
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username",username);
        return accountMapper.selectOne(wrapper);
    }
}
7,编写realm类
package com.bd13.springbootshiro.realm;

import com.bd13.springbootshiro.entity.Account;
import com.bd13.springbootshiro.service.AccountService;
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;

import java.util.HashSet;
import java.util.Set;

public class AccountRealm extends AuthorizingRealm {
     
    @Autowired
    private AccountService accountService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
     
        //获取当前登录的用户信息
        Subject subject= SecurityUtils.getSubject();
        Account account = (Account) subject.getPrincipal();
        //设置角色
        Set<String> roles=new HashSet<>();
        roles.add(account.getRole());
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(roles);
        //设置权限
        info.addStringPermission(account.getPerms());
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
     
        UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
        Account account = accountService.findByUsername(token.getUsername());
        if (account != null){
     
            return new SimpleAuthenticationInfo(account,account.getPassword(),getName());
        }
        return null;
    }
}
8,编写config类
package com.bd13.springbootshiro.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.bd13.springbootshiro.realm.AccountRealm;
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.Hashtable;
import java.util.Map;

@Configuration
public class ShiroConfig {
     

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
     
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置
        Map<String,String> map=new Hashtable<>();
        map.put("/main","authc");
//        map.put("/manage","perms[manage]");
//        map.put("/administrator","roles[administrator]");
        factoryBean.setFilterChainDefinitionMap(map);
        //设置登录页面
        factoryBean.setLoginUrl("/login");
        //设置未授权页面
        factoryBean.setUnauthorizedUrl("/unaurh");
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm){
     
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }


    @Bean
    public AccountRealm accountRealm(){
     
        return new AccountRealm();
    }

    @Bean
    public ShiroDialect shiroDialect(){
     
        return new ShiroDialect();
    }
}
9,编写controller类
package com.bd13.springbootshiro.controller;

import com.bd13.springbootshiro.entity.Account;
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.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AccountController {
     
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url")String url){
     
        return url;
    }
    @PostMapping("/login")
    public String login(String username, String password, Model model){
     
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try{
     
            subject.login(token);
            Account account= (Account) subject.getPrincipal();
            subject.getSession().setAttribute("account",account);
            return "index";
        }catch (UnknownAccountException e){
     
            model.addAttribute("msg","用户名错误!");
            return "login";
        }catch (IncorrectCredentialsException e){
     
            model.addAttribute("msg","密码错误!");
            return "login";
        }
    }

    @GetMapping("/unauth")
    @ResponseBody
    public String unauth(){
     
        return "未授权,无法访问!";
    }

    @GetMapping("/logout")
    public String logout(){
     
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "login";
    }
}
10,页面

login.html


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="shortcut icon" href="#"/>
head>
<body>
    <form action="/login" method="post">
        <table>
            <span th:text="${msg}" style="color: red">span>
            <tr>
                <td>用户名:td>
                <td>
                    <input type="text" name="username"/>
                td>
            tr>
            <tr>
                <td>密码:td>
                <td>
                    <input type="password" name="password"/>
                td>
            tr>
            <tr>
                <td>
                    <input type="submit" value="登录"/>
                td>
            tr>
        table>
    form>
body>
html>

index.html


<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="shortcut icon" href="#"/>
head>
<body>
    <h1>indexh1>
    <div th:if="${session.account != null}">
        <span th:text="${session.account.username}+'欢迎回来!'">span><a href="/logout">退出a>
    div>
    <a href="/main">maina> <br/>
    <div shiro:hasPermission="manage">
        <a href="manage">managea> <br/>
    div>
    <div shiro:hasRole="administrator">
        <a href="/administrator">administratora>
    div>
body>
html>

main.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="shortcut icon" href="#"/>
head>
<body>
    <h1>mainh1>
body>
html>

manage.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="shortcut icon" href="#"/>
head>
<body>
    <h1>manageh1>
body>
html>

administrator.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="shortcut icon" href="#"/>
head>
<body>
    <h1>administatorh1>
body>
html>
测试结果

普通用户登录
浅谈Shiro安全框架_第2张图片
管理员
浅谈Shiro安全框架_第3张图片
超级管理员
浅谈Shiro安全框架_第4张图片

代码下载地址

代码下载地址

你可能感兴趣的:(Note)