Shiro学习记录(详细)

Shiro学习记录

什么是 Shiro

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

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

Shiro 就是用来解决安全管理的系统化框架。

shiro核心组件

用户、角色、权限(三者关系)

会给角色赋予权限,给用户赋予角色

1、UsernamePasswordToken,Shiro 用来封装用户登录信息,使用用户的登录信息来创建令牌 Token。

2、SecurityManager,Shiro 的核心部分,负责安全认证和授权。

3、Suject,Shiro 的一个抽象概念,包含了用户信息。

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

5、AuthenticationInfo,用户的角色信息集合,认证时使用。

6、AuthorzationInfo,角色的权限信息集合,授权时使用。

7、DefaultWebSecurityManager,安全管理器,开发者自定义的 Realm 需要注入到 DefaultWebSecurityManager 进行管理才能生效。

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

Shiro 的运行机制如下图所示:

在这里插入图片描述

Spring Boot 整合 Shiro

1、创建 Spring Boot 应用,集成 Shiro 及相关组件,pom.xml:

<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>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>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.1.tmp</version>
</dependency>

<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</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>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Account.java

package com.monkey.springbootshrio.entity;

import lombok.Data;

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

数据库表:

在这里插入图片描述

2、自定义 Shiro 过滤器

package com.monkey.springbootshrio.realm;

import com.monkey.springbootshrio.entity.Account;
import com.monkey.springbootshrio.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;
    }


    /**
     * 认证(登录)
     * @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;//抛出用户不存在
    }
}

3、配置类

package com.monkey.springbootshrio.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.monkey.springbootshrio.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("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(defaultWebSecurityManager);
        //认证和授权(权限设置)
        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("/unauth");
        return factoryBean;
    }


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


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

}

编写认证和授权规则:

认证过滤器

anon:无需认证。

authc:必须认证。

authcBasic:需要通过 HTTPBasic 认证。

user:不一定通过认证,只要曾经被 Shiro 记录即可,比如:记住我。

授权过滤器

perms:必须拥有某个权限才能访问。

role:必须拥有某个角色才能访问。

port:请求的端口必须是指定值才可以。

rest:请求必须基于 RESTful,POST、PUT、GET、DELETE。

ssl:必须是安全的 URL 请求,协议 HTTPS。

例子:

创建 3 个页面,main.html、manage.html、administrator.html

访问权限如下:

1、必须登录才能访问 main.html

2、当前用户必须拥有 manage 授权才能访问 manage.html

3、当前用户必须拥有 administrator 角色才能访问 administrator.html

Shiro 整合 Thymeleaf

1、pom.xml 引入依赖(所有依赖见上pom文件dependency代码)

2、配置类添加 ShiroDialect

@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}

AccountController.java

package com.monkey.springbootshrio.controller;

import com.monkey.springbootshrio.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 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);//进入到realm里面认证方法
            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";
    }

}

login.html

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

index.html

<!DOCTYPE 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>index</title>
    <link rel="shortcut icon" href="#" />
</head>
<body>
    <h1>index</h1>
    <div th:if="${session.account != null}">
        <span th:text="${session.account.username}+'欢迎回来!'"></span>
        <span><a href="logout">退出</a></span>
    </div>
    <a href="/main">main</a> <br/>

    <div shiro:hasPermission="manage">
        <a href="/manage">manage</a> <br/>
    </div>

    <div shiro:hasRole="administrator">
        <a href="/administrator">administrator</a> <br/>
    </div>

</body>
</html>

运行截图(例:ls)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

完整源码获取github:

https://github.com/monkeyhlj/spring-study

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值