Shrio

页面报错

<link rel="shortcut icon" href="#"/>

简单的安全框架

官网:https://shiro.apache.org/

是一款java的主流的java的安全框架,它不依赖于任何容器,可以运行在javaEE和javaSE中,它的主要作用是对访问系统的用户进行身份认证,授权,会话管理,加密操作。

Shrio是用来解决安全管理的系统化的框架

Shrio的核心组件

用户,角色,权限

  • 角色赋予权限
  • 用户赋予角色

UsernamePasswordToken

Shrio用来封装用户的登录信息,使用户的登录信息来创建一个令牌Token

SecurityManager

Shrio的核心部分,负责安全认证和授权。

Subject

Shrio的抽象概念,包含了用户信息

Realm *

开发者自定义的模块,根据项目的需求,验证和授权的逻辑全部写在Realm里面

AuthenticatInfo

用户的角色信息集合,认证时使用

AuthorzationInfo

角色的权限信息集合,授权时使用

DefaultWebSecurityMannager

安全管理器,开发者自定义的Realm需要注入DefaultWebSecurityMannager才能生效

ShiroFilterFactoryBean

过滤器工厂,Shiro的基本运行机制是开发者定义的规则,Shiro去执行,具体的执行操作就是ShiroFilterFactoryBean创建的一个个Fillter对象来完成的

整合shrio使用SpringBoot

1.pom导入依赖:

<?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.6.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.southwind</groupId>
    <artifactId>shrio</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shrio</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--        shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>
<!--        mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
<!--        mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

构建工程mvn clean install

2.自定义shrio过滤器

a.持久层

mybatis plus

package com.southwind.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.southwind.entity.Account;
import org.springframework.stereotype.Repository;

@Repository
public interface AccountMapper extends BaseMapper<Account> {

}

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/text
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

b.服务层

接口:

package com.southwind.service;

import com.southwind.entity.Account;

public interface AccountService {
    public Account findByUsername(String name);
}

实现类:

package com.southwind.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.southwind.entity.Account;
import com.southwind.mapper.AccountMapper;
import com.southwind.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 name) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username",name);
        return accountMapper.selectOne(wrapper);
    }
}

c.编写realm

package com.southwind.realm;

import com.southwind.entity.Account;
import com.southwind.service.AccountService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

public class AccountRealm extends AuthorizingRealm {
    @Autowired
    private AccountService accountService;
    /**
     * 用户的角色信息   2.授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 用户的权限信息   1.认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @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;
    }
}

d.注入realm编写配置类

package com.southwind.config;

import com.southwind.entity.Account;
import com.southwind.realm.AccountRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class config {
//    注入工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager")DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean factoryBean =new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(manager);
        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();
    }

}

c.编写认证和授权规则

认证过滤器

  • anon:无需认证
  • authc:必需认证
  • authcBasic:需要通过HTTPBasic认证
  • user:不一定通过认证,只要曾经被Shiro记录即可,比如记住我

授权过滤器

  • perms:必须拥有摸个权限才能访问
  • role:必须有某个角色才能访问
  • port:请求的端口必须是指定值才可以
  • rest:请求必学基于RESTful,PUT POST GET DELETE
  • ssl:必须是安全的URL请求,协议HTTPS

思路

  1. 创建3个页面,main.html manage.html administator.html

    访问如下:

    • 必须登录才能访问main.html
    • 当前用户必学拥有manage授权才能访问manage.html
    • 当前用户必须拥有administator角色才能访问administator.html

3.具体细节:

a.在config配置类中添加

package com.southwind.config;

import com.southwind.entity.Account;
import com.southwind.realm.AccountRealm;
import org.apache.commons.collections.map.HashedMap;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class config {
//    注入工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager")DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean factoryBean =new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(manager);
//        权限设置
        Map<String,String> map = new HashMap<>();
        map.put("/main","authc");
        map.put("/manage","perms[manage]");
        map.put("/administator","roles[administator]");
        factoryBean.setFilterChainDefinitionMap(map);
        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();
    }

}

b.添加controller

package com.southwind.controller;

import com.southwind.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.*;

@Controller
public class AccountHandler {
    @GetMapping("/{url}")
    public String index(@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);
            com.southwind.entity.Account account=(Account)subject.getPrincipal();
            subject.getSession().setAttribute("account",account);
            return "index";
        }catch (UnknownAccountException e){
            e.printStackTrace();
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            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";
    }
}

c.配置视图解析器

创建index:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>index</h1>
    <div th:if="${session.account !=null}">
        <span th:text="${session.account.username}+'欢迎回来'"></span><br>
        <a href="/logout">退出</a>
        <a href="/main">mian</a>|<a href="/manage">manage</a>|<a href="/administrator">administrator</a>
    </div>
</body>
</html>

创建main:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>首页</h1>
</body>
</html>

创建manage:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>manage</h1>
</body>
</html>

创建administrator

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>administrator</h1>
</body>
</html>

创建login:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="shortcut icon" href="#"/>
</head>
<body>
    <form action="/login" method="post">
        <table>
            <span th:text="${msg}"></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>

thymeleaf整合shiro

posted on 2022-05-30 17:49  Steam残酷  阅读(170)  评论(0)    收藏  举报