shiro学习三(spring boot整合shiro读取数据库数据实现用户登录,权限认证)

一、本篇概述

如果大家看过我shiro类的其他博客,关于shiro的一些基本知识点就不再讲诉,本篇博客主要是讲诉Spring boot如何通过Java配置获取securityManager对象,如何通过调用数据库数据实现认证登录等功能,其中与数据库交互用的mybatis -plus。因为代码量比上篇博客多,我就不将所有代码粘贴出来了,主要展示一些重要的部分,如果需要整个demo的,可以下载我的案例

二、pom依赖

粘贴项目中需要引入的依赖信息‘

        <!-- 添加shrio依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!-- 添加mybatis-plus依赖 -->
        <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>
        <!-- 添加mysql依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!-- 添加阿里数据源依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

三、application.properties

因为含有数据库连接信息,所有该配置文件需要配置这些信息

server.port=8099
server.servlet.context-path=/shiro2

spring.datasource.druid.url=jdbc:mysql://localhost:3306/shiro?serverTimezone=UTC&useUnicode=true&charaterEncoding=utf-8&useSSL=false
spring.datasource.druid.username=root
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.password=123456


mybatis-plus.mapper-locations= classpath:mapper/*.xml

四、securityManager配置

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionsSecurityManager;
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;

/**
 * @Package: com.shior2
 * @ClassName: ShiroConfig
 * @Author: tanp
 * @Description: ${description}
 * @Date: 2020/7/3 14:11
 */

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("mySecurityManager") SecurityManager manager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(manager);
        return shiroFilterFactoryBean;
    }

    @Bean("mySecurityManager")
    public SessionsSecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(authRealm);
        return securityManager;
    }

    @Bean("authRealm")
    public AuthRealm getAuthRealm() {
        AuthRealm authRealm = new AuthRealm();
        return authRealm;
    }
}

在上面的代码中我们可以看到,与上一篇博客相比通过还是有很大变化的。

/**
     * @Description 获取subject对象
     * @Date 2020/7/3 10:07
     * @Author tanp
     */
    private static Subject getSubject(User user) {
        //下面这行代码过期了
        //Factory<SecurityManager>  factory = new IniSecurityManagerFactory("classpath:shiro-config.ini");
        //取代方法为:初始化一个DefaultSecurityManager对象,然后创建一个基于ini文件的Realm域,然后将域绑定到DefaultSecurityManager实例对象中
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        defaultSecurityManager.setRealm(iniRealm);
        //把securityManager实例绑定到SecurityUtils
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        return SecurityUtils.getSubject();
    }

      上面这段代码是上一篇博客获取subject对象的方法,我们可以看到,我们通过一个方法就已经获取到我们需要的Subject对象了,然后再通过subject对象做登录,判断是否具有权限即可。

    而在本篇的博客中,我们可以看到,我们是新建一个自定义relam对象,这对应着shiro学习二博客中的IniRealm对象,然后将relam对象设置到SecurityManage对象中,然后再将SecurityManage设置到ShiroFilterFactoryBean中,这些个对象也被Spring通过baen注解管理起来。做完这些配置,我们即可在需要subject对象的地方,通过SecurityUtils.getSubject();方法获取subject对象去做登录、验证。

四、自定义Relam对象

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.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import java.util.HashSet;
import java.util.List;

/**
 * @Package: com.shior2
 * @ClassName: AuthRealm
 * @Author: tanp
 * @Description: ${description}
 * @Date: 2020/7/3 14:14
 */
public class AuthRealm extends AuthorizingRealm {

    @Autowired
    @Qualifier("userServiceImpl")
    IUserService iUserService;

    /**
     * @Description  授权
     * @Date 2020/7/3 18:49
     * @Author tanp
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //能进入到这里,表示账号已经通过验证了
        String userName =(String) principals.getPrimaryPrincipal();
        //获取角色和权限
        List<String> permissions = iUserService.listPermissions(userName);
        List<String> roles = iUserService.listRoles(userName);
        //授权对象
        SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
        //把通过DAO获取到的角色和权限放进去
        s.setStringPermissions(new HashSet(permissions));
        s.setRoles(new HashSet(roles));
        return s;
    }

    /**
     * @Description  认证
     * @Date 2020/7/3 18:50
     * @Author tanp
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取账号密码
        UsernamePasswordToken t = (UsernamePasswordToken) token;
        String userName= token.getPrincipal().toString();
        String password= new String( t.getPassword());

        //获取数据库中的密码
        String password1 = iUserService.getPassword(userName);

        //如果为空就是账号不存在,如果不相同就是密码错误,但是都抛出AuthenticationException,而不是抛出具体错误原因,免得给破解者提供帮助信息
        if(null==password1 || !password1.equals(password)){
            return null;
        }
        //认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm
        return new SimpleAuthenticationInfo(userName,password,getName());
    }
}

     与上篇博客,直接通过ini配置文件路径new一个IniRealm对象不同,这篇博客我们自定义了realm对象,而自定义realm对象首先就是要让这个realm我们一般要继承AuthorizingRealm类,因为这个类里面就有实现接收用户认证信息和接收用户权限信息的两个方法,在将数据库中读取到的权限,角色,登录信息设置到两个方法中即可。

    在上面的代码中我们可以看到,在重写的认证方法中,我们是先获取用户登录的用户名和密码,然后通过用户名去数据库中查询对象该用户名对应的密码,将数据库查询到的密码和进入方法时获取到的密码对比,如果密码不一样,则返回null,用户认证不通过,如果一样则返回SimpleAuthenticationInfo对象,重写的认证方法时用来做登录使用。

   在重写的是授权方法中可以看到,是通过用户名获取到当前用户具备的角色名称和权限名称,然后设置SimpleAuthorizationInfo授权对象中。最后将授权对象返回出去。

五、登录、权限认证判断

private static boolean hasRole(String role) {
        Subject subject = SecurityUtils.getSubject();
        return subject.hasRole(role);
    }
private static boolean isPermited(String permission) {
        Subject subject = SecurityUtils.getSubject();
        return subject.isPermitted(permission);
    }
private static boolean login(User user) {
        //获取subject对象
        Subject subject = getSubject();
        //已经登录过,退出
        if (subject.isAuthenticated()) {
            subject.logout();
        }
        UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword());
        //调用login方法,将用户的数据token 最终传递到Realm中进行对比
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            System.out.println(user.getName() + "验证身份信息失败");
            return false;
        }
        return subject.isAuthenticated();
    }

判断是否有权限跟前面那篇博客一样,获取subject对象,通过subject对象来做登录,权限认证的操作。

六、数据库脚本

DROP DATABASE IF EXISTS shiro;
CREATE DATABASE shiro DEFAULT CHARACTER SET utf8;
USE shiro;
 
drop table if exists user;
drop table if exists role;
drop table if exists permission;
drop table if exists user_role;
drop table if exists role_permission;
 
create table user (
  id bigint auto_increment,
  name varchar(100),
  password varchar(100),
  constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB;
 
create table role (
  id bigint auto_increment,
  name varchar(100),
  constraint pk_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;
 
create table permission (
  id bigint auto_increment,
  name varchar(100),
  constraint pk_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;
 
create table user_role (
  uid bigint,
  rid bigint,
  constraint pk_users_roles primary key(uid, rid)
) charset=utf8 ENGINE=InnoDB;
 
create table role_permission (
  rid bigint,
  pid bigint,
  constraint pk_roles_permissions primary key(rid, pid)
) charset=utf8 ENGINE=InnoDB;

INSERT INTO `permission` VALUES (1,'addProduct');
INSERT INTO `permission` VALUES (2,'deleteProduct');
INSERT INTO `permission` VALUES (3,'editProduct');
INSERT INTO `permission` VALUES (4,'updateProduct');
INSERT INTO `permission` VALUES (5,'listProduct');
INSERT INTO `permission` VALUES (6,'addOrder');
INSERT INTO `permission` VALUES (7,'deleteOrder');
INSERT INTO `permission` VALUES (8,'editOrder');
INSERT INTO `permission` VALUES (9,'updateOrder');
INSERT INTO `permission` VALUES (10,'listOrder');
INSERT INTO `role` VALUES (1,'admin');
INSERT INTO `role` VALUES (2,'productManager');
INSERT INTO `role` VALUES (3,'orderManager');
INSERT INTO `role_permission` VALUES (1,1);
INSERT INTO `role_permission` VALUES (1,2);
INSERT INTO `role_permission` VALUES (1,3);
INSERT INTO `role_permission` VALUES (1,4);
INSERT INTO `role_permission` VALUES (1,5);
INSERT INTO `role_permission` VALUES (1,6);
INSERT INTO `role_permission` VALUES (1,7);
INSERT INTO `role_permission` VALUES (1,8);
INSERT INTO `role_permission` VALUES (1,9);
INSERT INTO `role_permission` VALUES (1,10);
INSERT INTO `role_permission` VALUES (2,1);
INSERT INTO `role_permission` VALUES (2,2);
INSERT INTO `role_permission` VALUES (2,3);
INSERT INTO `role_permission` VALUES (2,4);
INSERT INTO `role_permission` VALUES (2,5);
INSERT INTO `role_permission` VALUES (3,6);
INSERT INTO `role_permission` VALUES (3,7);
INSERT INTO `role_permission` VALUES (3,8);
INSERT INTO `role_permission` VALUES (3,9);
INSERT INTO `role_permission` VALUES (3,10);
INSERT INTO `user` VALUES (1,'zhang3','12345');
INSERT INTO `user` VALUES (2,'li4','abcde');
INSERT INTO `user_role` VALUES (1,1);
INSERT INTO `user_role` VALUES (2,2);

七、整体代码架构

 

八、案例下载链接

https://download.csdn.net/download/bird_tp/12587730

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值