0
点赞
收藏
分享

微信扫一扫

【shiro基础】springboot整合shiro

MaxWen 2022-02-07 阅读 77

目录

基础知识

shiro 功能

在这里插入图片描述
Authentication:认证;
Authorization:授权;
Session Management:会话管理,shiro拥有自己的session管理机制;
Cryptography:加密解密,管理如密码等数据;
Caching:缓存支持;
Concurrency:shiro 并发验证;
Testing:提供测试支持;
Run As:身份授权访问;
Remember Me:记住我;

架构

这部分资料比较多,不再啰嗦。
在这里插入图片描述
Subject:主体,即 “用户”;
SecurityManager:shiro安全管理器,管理 Subject、负责进行认证和授权、及会话、缓存的管理。
Authenticator:认证;
Authorizer:授权;
Realm:安全域,可以有 1 个或多个 Realm;;
SessionManager:绘画管理器;
Cryptography:加密解密模块。

依赖引入

完整项目引入包括:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springboot-shiro-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.3.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.8.0</version>
        </dependency>
    </dependencies>
</project>

自定义Realm域,完成认证及授权过程

定义登录接口,触发subject.login(token)

这一步主要完成认证数据(用户名、密码)的获取及token的创建,然后提交shiro进行认证。

@RequestMapping("/sublogin")
    public String subLogin(String userName,String password) {
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(userName,password);
        try {
            subject.login(token);
            subject = SecurityUtils.getSubject();
            // 设置shiro session (非必须)
            Session shiroSession = subject.getSession();
            shiroSession.setAttribute("user",subject.getPrincipal());
            return "OK:"+userName;
        }catch (UnknownAccountException e) {
            return "用户不存在";
        } catch (IncorrectCredentialsException e){
            return "密码不正确";
        }catch (AuthenticationException e) {
           return "登录失败";
        }
    }

自定义Realm域,用于完成认证及授权过程。

此步骤主要完成认证、授权两个过程,并对其中认证中的密码匹配器进行了重写(MD5).
认证: 主要用于构建认证对象(从数据库读取),用于提供给shiro进行认证操作。
授权: 主要用于读取(数据库)授权信息,提供给shiro,以完成授权检查。

package cn.com.demo.shiro.config;

import cn.com.demo.shiro.entity.TShiroUser;
import cn.com.demo.shiro.service.UserService;
import cn.com.demo.shiro.util.MD5;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
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 org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * 自定义域,完成认证及授权过程
 */
@Component
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        // 拿到当前用户
        Subject subject = SecurityUtils.getSubject();
        TShiroUser user  = (TShiroUser) subject.getPrincipal();
        // 设置权限
        simpleAuthorizationInfo.setStringPermissions(userService.getUserPermission(user.getId()));
        return simpleAuthorizationInfo;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        if(StringUtils.isEmpty(token.getUsername())){
            // 用户名为空
            return null;
        }
        TShiroUser user = userService.getUserByUserName(token.getUsername());
        if(user == null) {
            return null;
        }
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }

    /**
     * 密码匹配器
     * @return
     */
    @Override
    public CredentialsMatcher getCredentialsMatcher() {

        return new CredentialsMatcher() {
            @Override
            public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
                UsernamePasswordToken utoken = (UsernamePasswordToken) authenticationToken;
                //获得用户输入的密码
                String formPassword = new String(utoken.getPassword());
                //获得数据库中的密码
                String dbPassword = (String) authenticationInfo.getCredentials();
                try {
                    formPassword = MD5.encrypt(formPassword);
                    return dbPassword.equalsIgnoreCase(formPassword);
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
        };
    }
}

shiro 配置类,配置FactoryBean及web安全管理器

FactoryBean: 用于构建shiro环境及配置,配置各类资源权限,鉴权信息(如登录、授权失败等)、安全管理器等配置
web安全管理器: 用于向shiro提供自定义Realm域。
此过程中,完成Factory到Realm的关联。
在这里插入图片描述

package cn.com.demo.shiro.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.com.demo.shiro.entity.TShiroResPermission;
import cn.com.demo.shiro.service.UserService;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * shiro 配置类,配置FactoryBean及web安全管理器
 */
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Autowired DefaultWebSecurityManager defaultWebSecurityManager, @Autowired UserService userService){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // shiro 内置过滤器 org.apache.shiro.web.filter.mgt.DefaultFilter
        Map<String, String> map = new LinkedHashMap<>();
        // 登录相关免认证接口
        map.put("/auth/**","anon");
        map.put("/index","anon");
        // 需要demo:p1 权限
//        map.put("/demo/p1","perms[demo:p1]");
        // 需要demo:p2 权限
//        map.put("/demo/p2","perms[demo:p2]");
        // 从数据库中读取权限信息
        List<TShiroResPermission> tShiroResPermissionList = userService.getResPermission();
        for (TShiroResPermission tShiroResPermission : tShiroResPermissionList) {
            map.put(tShiroResPermission.getResPath(),"perms["+tShiroResPermission.getPermissionCode()+"]");
        }
        // 需要登录的接口
        map.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        // 设置登录页地址,前后端分离项目注意返回需要登录状态码等信息
        shiroFilterFactoryBean.setLoginUrl("/auth/login");
        // 设置未授权地址
        shiroFilterFactoryBean.setUnauthorizedUrl("/auth/forbidden");
        return shiroFilterFactoryBean;
    }

    /**
     * 安全管理器
     * @param userRealm
     * @return
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Autowired UserRealm userRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }
}

数据库设计

用户表

在这里插入图片描述

CREATE TABLE `t_shiro_user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

资源权限表

可对应实际生产的角色、菜单、按钮等跟权限有关的表
在这里插入图片描述

CREATE TABLE `t_shiro_res_permission` (
  `id` int NOT NULL AUTO_INCREMENT,
  `res_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '资源(如url)',
  `permission_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '权限代码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

用户权限表

对应用户权限信息;RBAC 权限方案中,还需要用户角色的参与,此表只用于简单表述用户的权限。
在这里插入图片描述

CREATE TABLE `t_shiro_user_permission` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` int NOT NULL COMMENT '用户id',
  `permission_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '权限代码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

完整源代码

举报

相关推荐

0 条评论