GVKun编程网logo

具有JavaConfig和Spring Boot的Apache Shiro JdbcRealm(什么是javaconfig)

29

在这篇文章中,我们将带领您了解具有JavaConfig和SpringBoot的ApacheShiroJdbcRealm的全貌,包括什么是javaconfig的相关情况。同时,我们还将为您介绍有关27.

在这篇文章中,我们将带领您了解具有JavaConfig和Spring Boot的Apache Shiro JdbcRealm的全貌,包括什么是javaconfig的相关情况。同时,我们还将为您介绍有关27. Spring Boot 缓存注解详解: @Cacheable、@CachePut、 @CacheEvict、@Caching、@CacheConfig、30分钟了解Shiro与Springboot的多Realm基础配置、Apache Shiro 实现 JdbcRealm 验证、Apache-shiro的内置Realm之jdbcRealm的知识,以帮助您更好地理解这个主题。

本文目录一览:

具有JavaConfig和Spring Boot的Apache Shiro JdbcRealm(什么是javaconfig)

具有JavaConfig和Spring Boot的Apache Shiro JdbcRealm(什么是javaconfig)

我正在尝试配置Spring Boot应用程序以使用Apache
Shiro作为其安全框架。我可以使用PropertiesRealm进行所有操作,现在我正在尝试使其与JdbcRealm和Spring
Boot的内置H2数据库一起使用。这是我pom.xml中的依赖项:

<dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-core</artifactId>    <version>1.2.3</version></dependency><dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-spring</artifactId>    <version>1.2.3</version></dependency><dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-web</artifactId>    <version>1.2.3</version></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency>    <groupId>com.h2database</groupId>    <artifactId>h2</artifactId></dependency>

我的schema.sql:

create table if not exists users (  username varchar(256),  password varchar(256),  enabled boolean);create table if not exists user_roles (  username varchar(256),  role_name varchar(256));

我的data.sql:

insert into users (username, password, enabled) values (''user'', ''04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb'', true);insert into user_roles (username, role_name) values (''user'', ''guest'');

还有我的WebSecurityConfig.java类,它配置所有内容:

package security;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.crypto.hash.Sha256Hash;import org.apache.shiro.realm.jdbc.JdbcRealm;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.filter.authc.AnonymousFilter;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import org.apache.shiro.web.filter.authc.LogoutFilter;import org.apache.shiro.web.filter.authc.UserFilter;import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.h2.server.web.WebServlet;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.embedded.ServletRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;import javax.sql.DataSource;import java.util.HashMap;import java.util.Map;@Configurationpublic class WebSecurityConfig {    @Bean(name = "shiroFilter")    public ShiroFilterFactoryBean shiroFilter() {        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();        Map<String, String> filterChainDefinitionMapping = new HashMap<>();        filterChainDefinitionMapping.put("/api/health", "authc,roles[guest],ssl[8443]");        filterChainDefinitionMapping.put("/login", "authc");        filterChainDefinitionMapping.put("/logout", "logout");        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMapping);        shiroFilter.setSecurityManager(securityManager());        shiroFilter.setLoginUrl("/login");        Map<String, Filter> filters = new HashMap<>();        filters.put("anon", new AnonymousFilter());        filters.put("authc", new FormAuthenticationFilter());        LogoutFilter logoutFilter = new LogoutFilter();        logoutFilter.setRedirectUrl("/login?logout");        filters.put("logout", logoutFilter);        filters.put("roles", new RolesAuthorizationFilter());        filters.put("user", new UserFilter());        shiroFilter.setFilters(filters);        return shiroFilter;    }    @Bean(name = "securityManager")    public DefaultWebSecurityManager securityManager() {        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        securityManager.setRealm(jdbcRealm());        return securityManager;    }    @Autowired    private DataSource dataSource;    @Bean(name = "realm")    @DependsOn("lifecycleBeanPostProcessor")    public JdbcRealm jdbcRealm() {        JdbcRealm realm = new JdbcRealm();        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();        credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);        realm.setCredentialsMatcher(credentialsMatcher);        realm.setDataSource(dataSource);        realm.init();        return realm;    }    @Bean    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {        return new LifecycleBeanPostProcessor();    }    @Bean    public ServletRegistrationBean h2servletRegistration() {        ServletRegistrationBean registration = new ServletRegistrationBean(new WebServlet());        registration.addUrlMappings("/console/*");        return registration;    }}

我的日志中没有看到任何错误。我尝试增加日志记录,然后将以下内容添加到application.properties中,但这并没有太大帮助。

logging.level.org.apache.shiro=debug

谢谢,

马特

答案1

小编典典

有几个正在发生的问题。

LifecycleBeanPostProcessor

问题是由于LifecycleBeanPostProcessor在config类中定义的事实。由于它是a,BeanPostProcessor因此必须将其初始化以处理所有其他bean。此外,其余WebSecurityConfig需求可能会急切初始化,因为它可能会影响LifecycleBeanPostProcessor

问题在于自动连线功能尚不可用,因为它也是一个BeanPostProcessor(即AutowiredAnnotationBeanPostProcessor)。这表示的DataSource值为null。

由于它为null,JdbcRealm因此将抛出NullPointerException。反过来,它被捕获AbstractAuthenticator并重新抛出AuthenticationException。在DefaultWebSecurityManager(实际上它的父DefaultSecurityManager),然后捕获它调用onFailedLogin它消除了“记住我”的cookie。

解决LifecycleBeanPostProcessor

最简单的解决方案是确保使用静态方法定义所有与基础架构相关的bean。这通知Spring不需要初始化整个配置类(即WebSecurityConfig)。再次

@Beanpublic static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {    return new LifecycleBeanPostProcessor();}

另外,您也可以在其自己的配置中隔离与基础结构相关的Bean。

更新

ShiroFilterFactoryBean

我也没意识到那个ShiroFilterFactoryBean工具BeanPostProcessorObjectFactory也可以实施一个非常有趣的情况BeanPostProcessor

问题在于,这阻止了data.sql的加载,这意味着应用程序在表中没有任何用户,因此身份验证将失败。

问题是data.sql是通过加载的DataSourceInitializedEvent。但是,由于急切的初始化DataSource(这是a的依赖项BeanPostProcessor),DataSourceInitializedEvent因此无法触发。这就是为什么您在日志中看到以下内容的原因:

无法发送事件以完成数据源初始化(未初始化ApplicationEventMulticaster)

确保data.sql加载

我看到一些选项可以使insert语句加载。

data.sql-> schema.sql

最简单的选项是将data.sql的内容移动到schema.sql。schema.sql仍在加载,因为它不需要触发事件来处理它。data.sql需要一个事件,以便在JPA初始化架构时可以使用相同的机制来加载数据。

整理订单

不幸的是,您不能简单地为ShiroFilterFactoryBeanstatic
定义,因为它依赖于其他bean定义。幸运的是,BeanPostProcessor在这种情况下,确实不需要。这意味着您可以更改代码以返回工厂bean的结果,该结果BeanPostProcessor将从等式中删除:

@Bean(name = "shiroFilter")public AbstractShiroFilter shiroFilter() throws Exception {    ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();    Map<String, String> filterChainDefinitionMapping = new HashMap<>();    filterChainDefinitionMapping.put("/api/health", "authc,roles[guest],ssl[8443]");    filterChainDefinitionMapping.put("/login", "authc");    filterChainDefinitionMapping.put("/logout", "logout");    shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMapping);    shiroFilter.setSecurityManager(securityManager());    shiroFilter.setLoginUrl("/login");    Map<String, Filter> filters = new HashMap<>();    filters.put("anon", new AnonymousFilter());    filters.put("authc", new FormAuthenticationFilter());    LogoutFilter logoutFilter = new LogoutFilter();    logoutFilter.setRedirectUrl("/login?logout");    filters.put("logout", logoutFilter);    filters.put("roles", new RolesAuthorizationFilter());    filters.put("user", new UserFilter());    shiroFilter.setFilters(filters);    return (AbstractShiroFilter) shiroFilter.getObject();}

插入用户

在data.sql中找到的insert语句不正确。它需要包括enabled列。例如:

insert into users values (''admin'', ''22f256eca1f336a97eef2b260773cb0d81d900c208ff26e94410d292d605fed8'',true);

27. Spring Boot 缓存注解详解: @Cacheable、@CachePut、 @CacheEvict、@Caching、@CacheConfig

27. Spring Boot 缓存注解详解: @Cacheable、@CachePut、 @CacheEvict、@Caching、@CacheConfig

 

 1、使用OGNL的命名规则来定义Key的值

@Cacheable(cacheNames = {"user"},key = "#root.methodName + ''['' + #id + '']''")
@Override
public User selectByPrimaryKey(Integer id) {
   return userMapper.selectByPrimaryKey(id);
}

 

 

 

 

2、自定义Key生成器

@Configuration
public class MyConfig {

    @Bean
    public KeyGenerator myKeyGenerator(){
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... params) {
                String key = o.getClass().getSimpleName()+"."+method.getName()+Arrays.asList(params);
                return key;
            }
        };
    }

}

 

key 属性和keyGenerator属性只能二选一

@Cacheable(cacheNames = {"user"},keyGenerator = "myKeyGenerator")
@Override
public User selectByPrimaryKey(Integer id) {
  return userMapper.selectByPrimaryKey(id);
}

 

 

3、加条件过滤

/**condition成立的条件缓存,unless成立的条件不缓存。以下实例含义为:id > 1 且 id != 2 的缓存
*
* 1、condition:id >1的会被缓存,只执行一次查询SQL,id <= 1的每次查询都会执行SQL,#a0是取第一个参数,也可以用“#参数名” 即:#id
* 2、unless: id==2的不缓存
* 3、sync: 异步方式缓存
* sync 和 unless 不能同时支持,否则会报错

*/
@Cacheable(cacheNames = {"user"},keyGenerator = "myKeyGenerator",condition = "#a0>1", unless="#id==2", sync=true) @Override public User selectByPrimaryKey(Integer id) { return userMapper.selectByPrimaryKey(id); }

 

 

 

4、缓存更新  @CachePut

 

/**
 * @CachePut:既调用方法,又更新缓存数据;同步更新缓存
 * 修改了数据库的某个数据,同时更新缓存;
 * 运行时机:
 *  1、先调用目标方法
 *  2、将目标方法的结果缓存起来
 *
 * 测试步骤:
 *  1、查询1号员工;查到的结果会放在缓存中;
 *          key:1  value:name:张三
 *  2、以后查询还是之前的结果
 *  3、更新1号员工;【name:zhangsan;age:10】
 *          将方法的返回值也放进缓存了;
 *          key:传入的employee对象  值:返回的employee对象;
 *  4、查询1号员工?
 *      应该是更新后的员工;
 *          key = "#record.id":使用传入的参数的员工id;
 *          key = "#result.id":使用返回后的id
 *             @Cacheable的key是不能用#result
 *      为什么是没更新前的?【1号员工没有在缓存中更新】
 *
 */
@CachePut(cacheNames = {"user"},key = "#record.id")
@Override
public User updateByPrimaryKeySelective(User record) {
    userMapper.updateByPrimaryKeySelective(record);
    return userMapper.selectByPrimaryKey(record.getId());
}

 

4、缓存清除@CacheEvict
/**
     * @CacheEvict:缓存清除
     *  key:指定要清除的数据
     *  allEntries = true:指定清除这个缓存中所有的数据
     *  beforeInvocation = false:缓存的清除是否在方法之前执行
     *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
     *
     *  beforeInvocation = true:
     *      代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
     *
     *
     */
    @CacheEvict(value="emp",beforeInvocation = true/*key = "#id",*/)
    @Override
    public int deleteByPrimaryKey(Integer id) {
        System.out.println("delete user : " + id);
        return id;
        //return userMapper.deleteByPrimaryKey(id);
    }

 

5、复杂的 

/**
 * 复杂的缓存规则:
 * 1.以name查询还会去查询数据库:因为有@CachePut注解,所以这方法一定要执行的,@CachePut把方法执行的结果缓存到缓存
 * 2. (1), (1) : 每次都会执行SQL,因为有@CachePut
 *   (1),(2): (1)执行SQL,不执行
 *
 *
 * */
@Caching(
    cacheable = {
            @Cacheable(cacheNames = {"user"},key="#name") //1)根据name查询user
    },
    put = {
        @CachePut(cacheNames = {"user"},key="#result.id") //(2) 根据id查询user 以另一种key将查询出的结果缓存到缓存中
    }
)
@Override
public User selectByName(String name) {
    return userMapper.selectByName(name);
}

 

 

6. 全局参数提取 @CacheConfig

@Service
@CacheConfig(cacheNames={"user"},keyGenerator = "myKeyGenerator")
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;


    @CacheEvict(/*value="emp",*/ beforeInvocation = true/*key = "#id",*/)
    @Override
    public int deleteByPrimaryKey(Integer id) {
        System.out.println("delete user : " + id);
        return id;
        //return userMapper.deleteByPrimaryKey(id);
    }
}

 

30分钟了解Shiro与Springboot的多Realm基础配置

30分钟了解Shiro与Springboot的多Realm基础配置

写在前面的话:

我之前写过两篇与shiro安全框架有关的博文,居然能够广受欢迎实在令人意外。说明大家在互联网时代大伙对于安全和登录都非常重视,无论是大型项目还是中小型业务,普遍都至少需要登录与认证的逻辑封装。相较于SpringSecurity而言,Shrio更轻量无过多依赖和便于独立部署的特点更收到开发者的欢迎。本篇博客只作为前两篇对于shiro使用的基础补充,我只谈谈如何在springboot项目中配置多角色验证。

一、场景介绍

假设在我们的项目中需要有前台用户登录和后台系统管理员登录两种验证方式。当然在传统的业务逻辑中用户和管理员可以使用不同的角色加以区分,假设现在的逻辑是用户与系统管理员分别保存在不同的表中并且也分别对应了不同的角色(role)与权限(permission)。换句话说,从业务上看相同的用户名和密码如果是在前台页面登录可能对应的是普通用户,从后台登录则对应某板块的系统管理。面对这样的需求我们可以在shiro框架中配置多个realm,再配合上认证策略来执行。

二、代码讲解

与单一realm相同,首先根据不同的登录认证要求创建不同的realm。这里只提供作为后台系统管理员的realm代码实例:

// 系统管理员专用
public class AdministratorRealm extends AuthorizingRealm {
    @Autowired
    private AdministratorRegisterService administratorRegisterService;
    @Autowired
    private PasswordSupport passwordSupport;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        String username = (String) principals.getPrimaryPrincipal();
        Administrator administrator = administratorRegisterService.getAdministratorByName(username);
        for (Role r : administrator.getRoles()) {
            authorizationInfo.addRole(r.getRoleName());
        }
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        Administrator administrator = administratorRegisterService.getAdministratorByName(username);
        if (administrator == null) {
            throw new UnknownAccountException();
        }
        if (administrator.isLocked()) {
            throw new LockedAccountException();
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(administrator.getUsername(),
                administrator.getPassword(), ByteSource.Util.bytes(passwordSupport.credentialsSalt(administrator)),
                getName());

        return authenticationInfo;
    }

}

doGetAuthenticationInfo方法负责用户名和密码验证,doGetAuthorizationInfo方法负责角色和权限的分配, passwordSupport是一个自定义的类负责password加密和生成salt功能。

/**
 * 密码辅助方法
 * 
 * @author learnhow
 *
 */
@Component
public class PasswordSupport {
    public static final String ALGORITHM_NAME = "md5";
    public static final int HASH_ITERATIONS = 2;/**
     * 针对系统管理生成salt和加密密码
     * 
     * @param administrator
     */
    public void encryptPassword(Administrator administrator) {
        administrator.setSalt(new SecureRandomNumberGenerator().nextBytes().toHex());
        String newPassword = new SimpleHash(ALGORITHM_NAME, administrator.getPassword(),
                ByteSource.Util.bytes(credentialsSalt(administrator)), HASH_ITERATIONS).toHex();
        administrator.setPassword(newPassword);
    }/**
     * 对Administrator的salt生成规则
     * 
     * @param administrator
     * @return
     */
    public String credentialsSalt(Administrator administrator) {
        return administrator.getSalt() + administrator.getEmail();
    }
}

AdministratorRegisterService是服务组件负责通过name从数据库中查询。

在Shiro中无论是单一realm还是多个realm都需要对SecurityManager进行配置。

@Configuration
public class ShiroConfig {
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName(PasswordSupport.ALGORITHM_NAME);
        hashedCredentialsMatcher.setHashIterations(PasswordSupport.HASH_ITERATIONS);
        return hashedCredentialsMatcher;
    }

    @Bean
    public AdministratorRealm getAdministatorRealm() {
        AdministratorRealm realm = new AdministratorRealm();
        realm.setName("AdministratorRealm");
        realm.setCredentialsMatcher(hashedCredentialsMatcher());
        return realm;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        securityManager.setAuthenticator(modularRealmAuthenticator);

        List<Realm> realms = new ArrayList<>();
        // TODO-多个realms进配置在这里 
        realms.add(getAdministatorRealm());
        securityManager.setRealms(realms);
        return securityManager;
    }
}

ModularRealmAuthenticator的setAuthenticationStrategy方法中配置认证策略。Shiro提供了三种策略:AllSuccessFulStrategy, AtLeastOneSuccessFulAtrategy, FirstSuccessFulStrategy,默认使用AtLeastOneSuccessFulAtrategy,通常不需要特别配置。

三、注意事项

1.多realm认证只会抛出AuthenticationException,因此如果要想在外部判断到底是在认证的哪一步发生的错误需要自己定义一些异常类型。

2.shiro没有提供根据条件指定realm的功能,如果需要实现这样的功能只能通过继承与重写来实现,这里没有涉及需要深入探讨的同学最好根据自己的实际情况专门研究。

 

写在后面的话:

最近有不少朋友在看了我的博客以后加我的QQ或者发邮件要求提供演示源码,为了方便交流我索性建了一个技术交流群,今后有些源码我可能就放群资料里面了。当然之前的一些东西还在补充中,有些问题也希望大伙能共同交流。QQ群号:960652410

Apache Shiro 实现 JdbcRealm 验证

Apache Shiro 实现 JdbcRealm 验证

数据库中创建一个用户表,字段可以很简单。

drop database if exists shiro;
create database shiro;
use shiro;

create table users (
  id bigint auto_increment,
  username varchar(100),
  password varchar(100),
  password_salt varchar(100),
  constraint pk_users primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_users_username on users(username);

create table user_roles(
  id bigint auto_increment,
  username varchar(100),
  role_name varchar(100),
  constraint pk_user_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_user_roles on user_roles(username, role_name);

create table roles_permissions(
  id bigint auto_increment,
  role_name varchar(100),
  permission varchar(100),
  constraint pk_roles_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_roles_permissions on roles_permissions(role_name, permission);

insert into users(username,password) values (''zhang'',''123'');
insert into users(username,password) values (''wl'',''123'');
insert into users(username,password) values (''lx'',''123'');

配置 shiro-jdbc-reaml.ini

[main]
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro
dataSource.username=root
dataSource.password=root
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm

进行单元测试

    @Test
    public void testJDBCRealm() {
        //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
        Factory<SecurityManager> factory =new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");

        //2、得到SecurityManager实例 并绑定给SecurityUtils
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("wl", "123");

        try {
            //4、登录,即身份验证
            subject.login(token);
        } catch (AuthenticationException e) {
            //5、身份验证失败
            e.printStackTrace();
        }

        Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录

        //6、退出
        subject.logout();
    }

 

Apache-shiro的内置Realm之jdbcRealm

Apache-shiro的内置Realm之jdbcRealm

Realm简介:

重要的事再说一遍,数据域,Shiro和安全数据的连接器,好比jdbc连接数据库; 通过realm获取认证授权相关信息

realm作用:

Shiro 从 Realm 获取安全数据

默认自带的realm:

idae查看realm继承关系,有默认实现和自定义继承的realm

两个概念:

principal : 主体的标示,可以有多个,但是需要具有唯一性,常见的有用户名,手机号,邮箱等

credential:凭证, 一般就是密码

所以一般我们说 principal + credential 就账号 + 密码

开发中,往往是自定义realm , 即集成 AuthorizingRealm

JdbcRealm:

创建jdbcRealm数据库表:

sql语句:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for roles_permissions
-- ----------------------------
DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `permission` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `idx_roles_permissions`(`role_name`, `permission`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES (4, ''admin'', ''video:*'');
INSERT INTO `roles_permissions` VALUES (3, ''role1'', ''video:buy'');
INSERT INTO `roles_permissions` VALUES (2, ''role1'', ''video:find'');
INSERT INTO `roles_permissions` VALUES (5, ''role2'', ''*'');
INSERT INTO `roles_permissions` VALUES (1, ''root'', ''*'');

-- ----------------------------
-- Table structure for user_roles
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `role_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `idx_user_roles`(`username`, `role_name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES (1, ''woxbwo'', ''role1'');
INSERT INTO `user_roles` VALUES (2, ''woxbwo'', ''role2'');
INSERT INTO `user_roles` VALUES (4, ''zbbiex'', ''admin'');
INSERT INTO `user_roles` VALUES (3, ''zbbiex'', ''root'');

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password_salt` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `idx_users_username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, ''woxbwo'', ''456'', NULL);
INSERT INTO `users` VALUES (2, ''zbbiex'', ''123'', NULL);

SET FOREIGN_KEY_CHECKS = 1;

1、方式一: 

创建jdbcrealm.ini文件,放到resource目录下,文件内容为:

#注意 文件格式必须为ini,编码为ANSI

#声明Realm,指定realm类型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm

#配置数据源
#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource

dataSource=com.alibaba.druid.pool.DruidDataSource

# mysql-connector-java 5 用的驱动url是com.mysql.jdbc.Driver,mysql-connector-java6以后用的是com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.cj.jdbc.Driver

#避免安全警告
dataSource.url=jdbc:mysql://127.0.0.1:3306/is-shiro-test?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false

dataSource.username=root

dataSource.password=123456

#指定数据源
jdbcRealm.dataSource=$dataSource

#开启查找权限
jdbcRealm.permissionsLookupEnabled=true

#指定SecurityManager的Realms实现,设置realms,可以有多个,用逗号隔开
securityManager.realms=$jdbcRealm

上代码:

    @Test
    public void shiroJdbcRealmTest(){
        //创建SecurityManager工厂,通过配置文件ini创建
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");

        SecurityManager securityManager = factory.getInstance();

        //将securityManager 设置到当前运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();

        //用户输入的账号密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("woxbwo", "456");

        subject.login(usernamePasswordToken);

        //org.apache.shiro.realm.jdbc.JdbcRealm

        System.out.println(" 认证结果:"+subject.isAuthenticated());

        System.out.println(" 是否有对应的role1角色:"+subject.hasRole("role1"));

        System.out.println("是否有video:find权限:"+ subject.isPermitted("video:find"));

    }

测试结果:

认证结果:true
02:34:43.991 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set.  Checking for a cacheManager...
02:34:43.992 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set.  Authorization cache cannot be obtained.
是否有对应的role1角色:true
02:34:44.089 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set.  Checking for a cacheManager...
02:34:44.089 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set.  Authorization cache cannot be obtained.
是否有video:find权限:true

 

方式二 :

上代码:

@Test
    public void shiroJdbcRealmTest2(){
        String driveName = "com.mysql.cj.jdbc.Driver";
        String dbUrl = "jdbc:mysql://127.0.0.1:3306/is-shiro-test?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false";
        String userName = "root";
        String pwd = "123456";
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driveName);
        ds.setUrl(dbUrl);
        ds.setUsername(userName);
        ds.setPassword(pwd);

        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setPermissionsLookupEnabled(true);
        jdbcRealm.setDataSource(ds);

        securityManager.setRealm(jdbcRealm);

        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();

        //用户输入的账号密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zbbiex", "123");

        subject.login(usernamePasswordToken);


        System.out.println(" 认证结果:"+subject.isAuthenticated());

        System.out.println(" 是否有对应的role1角色:"+subject.hasRole("role1"));

        System.out.println("是否有video:find权限:"+ subject.isPermitted("video:find"));

        System.out.println("是否有任意权限:"+ subject.isPermitted("aaaa:xxxxxxxxx"));
    }

 测试结果:

认证结果:true
02:54:26.188 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set.  Checking for a cacheManager...
02:54:26.188 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set.  Authorization cache cannot be obtained.
是否有对应的role1角色:false
02:54:26.276 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set.  Checking for a cacheManager...
02:54:26.276 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set.  Authorization cache cannot be obtained.
是否有video:find权限:true
02:54:26.363 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set.  Checking for a cacheManager...
02:54:26.363 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set.  Authorization cache cannot be obtained.
是否有任意权限:true

 

我们今天的关于具有JavaConfig和Spring Boot的Apache Shiro JdbcRealm什么是javaconfig的分享就到这里,谢谢您的阅读,如果想了解更多关于27. Spring Boot 缓存注解详解: @Cacheable、@CachePut、 @CacheEvict、@Caching、@CacheConfig、30分钟了解Shiro与Springboot的多Realm基础配置、Apache Shiro 实现 JdbcRealm 验证、Apache-shiro的内置Realm之jdbcRealm的相关信息,可以在本站进行搜索。

本文标签: