Idea Spring-boot整合shiro安全框架

shiro (java安全框架)

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

主要功能

三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
  从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
  Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
github:
https://github.com/1315998513/spring-boot-shiro

搭建spring-boot基础环境:

新建Spring-boot项目
Idea Spring-boot整合shiro安全框架_第1张图片
pom.xml:


<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.3.1.RELEASEversion>
        <relativePath/> 
    parent>
    <groupId>com.liuxigroupId>
    <artifactId>spring-boot-shiroartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>spring-boot-shironame>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
            
            <exclusions>
                
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
            exclusions>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-log4jartifactId>
            <version>1.3.8.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
        dependency>
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>1.1.1version>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelperartifactId>
            <version>3.7.5version>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <scope>providedscope>
        dependency>
        
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>jstlartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-tomcatartifactId>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>org.apache.tomcat.embedgroupId>
            <artifactId>tomcat-embed-jasperartifactId>
            
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <optional>trueoptional>
        dependency>

        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aopartifactId>
            <version>4.3.12.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.8.7version>
        dependency>

        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.1.10version>
        dependency>
        
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-coreartifactId>
            <version>1.2.2version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.2.2version>
        dependency>

    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

整合mybatis:

添加依赖
yml配置:

server:
  port: 8080
  servlet:  #启动jsp支持
    init-parameters:
      development: true
    contextPath: /spssm
spring:
  mvc:
    view:
      prefix: /WEB-INF/page/
      suffix: .jsp
  datasource:
    url: jdbc:mysql://*:3306/*?useUnicode=true&characterEncoding=utf-8
    username: root
    password: *
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  mapperLocations: classpath:com/liuxi/mapper/xml/*.xml

整合德鲁伊连接池:

添加依赖
druid.properties:

log4j.rootLogger=info,A1,DRF
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5p [%F:%L] : %m%n

log4j.appender.DRF=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRF.Threshold=DEBUG
log4j.appender.DRF.DatePattern='.'yyyy-MM-dd
log4j.appender.DRF.File=logs/pms.log
log4j.appender.DRF.Append=true
log4j.appender.DRF.layout=org.apache.log4j.PatternLayout
log4j.appender.DRF.layout.ConversionPattern=[%-5p][%d{yyyyMMdd HH:mm:ss,SSS}][%C{1}:%L] %m%n

#log4j.logger.com.ibatis=DEBUG
#log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
#log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
#log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
#log4j.logger.java.sql.Statement=DEBUG
#log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.com.liuxi.mapper=DEBUG

config下新建MybatisConfig:

package com.liuxi.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * 数据库连接池配置
 *
 * @author 
 */
@Configuration
@PropertySource("classpath:druid.properties")
public class MybatisConfig {

	private Logger logger = LoggerFactory.getLogger(MybatisConfig.class);

	@Value("${spring.datasource.url}")
	private String dbUrl;

	@Value("${spring.datasource.username}")
	private String username;

	@Value("${spring.datasource.password}")
	private String password;

	@Value("${spring.datasource.driver-class-name}")
	private String driverClassName;

	@Value("${spring.datasource.druid.initialSize}")
	private int initialSize;

	@Value("${spring.datasource.druid.minIdle}")
	private int minIdle;

	@Value("${spring.datasource.druid.maxActive}")
	private int maxActive;

	@Value("${spring.datasource.druid.maxWait}")
	private int maxWait;

	@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
	private int timeBetweenEvictionRunsMillis;

	@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
	private int minEvictableIdleTimeMillis;

	@Value("${spring.datasource.druid.validationQuery}")
	private String validationQuery;

	@Value("${spring.datasource.druid.testWhileIdle}")
	private boolean testWhileIdle;

	@Value("${spring.datasource.druid.testOnBorrow}")
	private boolean testOnBorrow;

	@Value("${spring.datasource.druid.testOnReturn}")
	private boolean testOnReturn;

	@Value("${spring.datasource.druid.filters}")
	private String filters;

	@Value("${spring.datasource.druid.logSlowSql}")
	private String logSlowSql;

	/**
	 * 数据库连接池
	 *
	 * @return
	 */
	@Bean("druidDataSource")
	public DataSource druidDataSource() {
		DruidDataSource datasource = new DruidDataSource();
		datasource.setUrl(dbUrl);
		datasource.setUsername(username);
		datasource.setPassword(password);
		datasource.setDriverClassName(driverClassName);
		datasource.setInitialSize(initialSize);
		datasource.setMinIdle(minIdle);
		datasource.setMaxActive(maxActive);
		datasource.setMaxWait(maxWait);
		datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
		datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
		datasource.setValidationQuery(validationQuery);
		datasource.setTestWhileIdle(testWhileIdle);
		datasource.setTestOnBorrow(testOnBorrow);
		datasource.setTestOnReturn(testOnReturn);
		try {
			datasource.setFilters(filters);
		} catch (SQLException e) {
			logger.error("druid configuration initialization filter", e);
		}
		return datasource;
	}


	/**
	 * 访问druid监控信息,查看sql语句执行情况 需要servlet支持
	 *
	 * http://127.0.0.1:8080/spssm/druid/login.html
	 *
	 * @return
	 */
	@Bean
	public ServletRegistrationBean druidServletRegistration() {
		ServletRegistrationBean registration = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
		// 添加初始化参数:initParams

		// 白名单:
		registration.addInitParameter("allow", "127.0.0.1");
		// IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not
		// permitted to view this page.
		registration.addInitParameter("deny", "");
		// 登录查看信息的账号密码.
		registration.addInitParameter("loginUsername", "admin");
		registration.addInitParameter("loginPassword", "admin");
		// 是否能够重置数据.
		registration.addInitParameter("resetEnable", "false");
		return registration;
	}

	/**
	 * 过滤druid
	 *
	 * @return
	 */
	@Bean
	public FilterRegistrationBean druidStatFilter() {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());

		// 添加过滤规则.
		filterRegistrationBean.addUrlPatterns("/*");

		// 添加不需要忽略的格式信息.
		filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
		return filterRegistrationBean;
	}
}

Idea Spring-boot整合shiro安全框架_第2张图片

整合事务:

添加依赖
在config新建:

package com.liuxi.config;

import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

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

/**
 * 事务拦截器
 */
//@Configuration
public class TransactionAopConfig {

    /**
     * 事务拦截器
     */
    @Bean("txInterceptor")
    TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx) {
        return new TransactionInterceptor(tx, transactionAttributeSource());
    }

    /**
     * 切面拦截规则 参数会自动从容器中注入
     */
    @Bean
    public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) {
        AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();
        pointcutAdvisor.setAdvice(txInterceptor);
        pointcutAdvisor.setExpression("execution (* com.liuxi.service.*.*(..))");
        return pointcutAdvisor;
    }

    /**
     * 事务拦截类型
     */
    @Bean("txSource")
    public TransactionAttributeSource transactionAttributeSource() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        /* 只读事务,不做更新操作 */
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        /* 当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务 */
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // requiredTx.setTimeout(5);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("batch*", requiredTx);
        txMap.put("select*", readOnlyTx);
        source.setNameMap(txMap);
        return source;
    }

}

整合log4j:

添加依赖
log4j.properties:

log4j.rootLogger=info,A1,DRF
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5p [%F:%L] : %m%n

log4j.appender.DRF=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRF.Threshold=DEBUG
log4j.appender.DRF.DatePattern='.'yyyy-MM-dd
log4j.appender.DRF.File=logs/pms.log
log4j.appender.DRF.Append=true
log4j.appender.DRF.layout=org.apache.log4j.PatternLayout
log4j.appender.DRF.layout.ConversionPattern=[%-5p][%d{yyyyMMdd HH:mm:ss,SSS}][%C{1}:%L] %m%n

#log4j.logger.com.ibatis=DEBUG
#log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
#log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
#log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
#log4j.logger.java.sql.Statement=DEBUG
#log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.com.liuxi.mapper=DEBUG

测试运行

新建controller:

package com.liuxi.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

    @RequestMapping("index")
    public String index(){
        System.out.println(666);
        return "index";
    }
}

新建index.jsp:
Idea Spring-boot整合shiro安全框架_第3张图片
index.jsp:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2020/07/23
  Time: 下午 1:01
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hellotitle>
head>
<body>
hello
body>
html>

访问:http://127.0.0.1:8080/spssm/index
在这里插入图片描述

数据库建表:

数据库有用户(user)、角色(role)、权限(permission)三个实体,除了实体表以外,为了实现表间用户与角色、角色与权限多对多的表间关系,所以产生了user_role、role_permission两张关系表。在下图中,使用红线将表的外键标记了出来,但为了方便并没有在表中创建外键,我们手动进行维护。
参考:
Idea Spring-boot整合shiro安全框架_第4张图片
user:
在这里插入图片描述
role:
在这里插入图片描述
permission:
Idea Spring-boot整合shiro安全框架_第5张图片
user_role:
Idea Spring-boot整合shiro安全框架_第6张图片
role_permission:
Idea Spring-boot整合shiro安全框架_第7张图片
编写sql语句:根据用户id查询出对应的权限:

SELECT DISTINCT
	*
FROM
	permission
WHERE
	id IN (
		SELECT
			rp.pid
		FROM
			USER u
		LEFT JOIN user_role ur ON u.id = ur.uid
		LEFT JOIN role_permission rp ON ur.rid = rp.rid
		WHERE
			u.id = 1
	)

结果:
Idea Spring-boot整合shiro安全框架_第8张图片
生成实体类,mapper,mapperxml:

package com.liuxi.entity;

public class User {
    private Integer id;

    private String username;

    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username == null ? null : username.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }
}

usermapper:

package com.liuxi.mapper;

import com.liuxi.entity.User;

public interface UserMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);

    User selectByName(String uname);
}

service:

package com.liuxi.service;

import com.liuxi.entity.User;

public interface UserService {

    int deleteByPrimaryKey(Integer id) throws Exception;

    int insert(User record) throws Exception;

    int insertSelective(User record) throws Exception;

    User selectByPrimaryKey(Integer id) throws Exception;

    int updateByPrimaryKeySelective(User record) throws Exception;

    int updateByPrimaryKey(User record) throws Exception;

    User selectByName(String uname) throws  Exception;

}

userserviceImpl:

package com.liuxi.impl;

import com.liuxi.entity.User;
import com.liuxi.mapper.UserMapper;
import com.liuxi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public int deleteByPrimaryKey(Integer id) throws Exception {
        return userMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insert(User record) throws Exception {
        return userMapper.insert(record);
    }

    @Override
    public int insertSelective(User record) throws Exception {
        return userMapper.insertSelective(record);
    }

    @Override
    public User selectByPrimaryKey(Integer id) throws Exception {
        return userMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(User record) throws Exception {
        return userMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(User record) throws Exception {
        return userMapper.updateByPrimaryKey(record);
    }

    @Override
    public User selectByName(String uname) throws Exception {
        return userMapper.selectByName(uname);
    }
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.liuxi.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="com.liuxi.entity.User">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="username" property="username" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
    </resultMap>


  <select id="selectByName" resultType="com.liuxi.entity.User">
    select * from user where username=#{uname}
  </select>
</mapper>

psermission:

package com.liuxi.entity;

public class Permission {
    private Integer id;

    private String name;

    private String url;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url == null ? null : url.trim();
    }
}

permissionMapper:

package com.liuxi.mapper;

import com.liuxi.entity.Permission;

import java.util.List;

public interface PermissionMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Permission record);

    int insertSelective(Permission record);

    Permission selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Permission record);

    int updateByPrimaryKey(Permission record);

    List<Permission> selectByUid(Integer uid);
}

service:

package com.liuxi.service;

import com.liuxi.entity.User;

public interface UserService {

    int deleteByPrimaryKey(Integer id) throws Exception;

    int insert(User record) throws Exception;

    int insertSelective(User record) throws Exception;

    User selectByPrimaryKey(Integer id) throws Exception;

    int updateByPrimaryKeySelective(User record) throws Exception;

    int updateByPrimaryKey(User record) throws Exception;

    User selectByName(String uname) throws  Exception;

}

impl:

package com.liuxi.impl;

import com.liuxi.entity.Permission;
import com.liuxi.mapper.PermissionMapper;
import com.liuxi.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class PermissionServiceImpl implements PermissionService {

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public int deleteByPrimaryKey(Integer id) throws Exception {
        return permissionMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insert(Permission record) throws Exception {
        return permissionMapper.insert(record);
    }

    @Override
    public int insertSelective(Permission record) throws Exception {
        return permissionMapper.insertSelective(record);
    }

    @Override
    public Permission selectByPrimaryKey(Integer id) throws Exception {
        return permissionMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(Permission record) throws Exception {
        return permissionMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(Permission record) throws Exception {
        return permissionMapper.updateByPrimaryKey(record);
    }

    @Override
    public List<Permission> selectByUid(Integer uid) throws Exception {
        return permissionMapper.selectByUid(uid);
    }
}

mapperXml:加入之前写好的SQL
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.liuxi.mapper.PermissionMapper">
    <resultMap id="BaseResultMap" type="com.liuxi.entity.Permission">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="url" property="url" jdbcType="VARCHAR"/>
    </resultMap>


    <select id="selectByUid" resultType="com.liuxi.entity.Permission">
      SELECT DISTINCT
          *
      FROM
          permission
      WHERE
          id IN (
              SELECT
                  rp.pid
              FROM
                  USER u
              LEFT JOIN user_role ur ON u.id = ur.uid
              LEFT JOIN role_permission rp ON ur.rid = rp.rid
              WHERE
                  u.id = #{uid}
          )
  </select>

</mapper>

Config添加登录授权类AuthRealm

package com.liuxi.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.liuxi.entity.Permission;
import com.liuxi.entity.User;
import com.liuxi.service.PermissionService;
import com.liuxi.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Component
public class AuthRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    // 认证.登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		User user = null;
		try {
			UsernamePasswordToken utoken = (UsernamePasswordToken) token;// 获取用户输入的token
			String username = utoken.getUsername();
			user = userService.selectByName(username);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());// 放入shiro.调用CredentialsMatcher检验密码
    }

    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        User user = (User) principal.fromRealm(this.getClass().getName()).iterator().next();// 获取session中的用户
        // 当前用户在系统上有什么权限,把拥有的权限设置到permissions
        List<String> permissions = new ArrayList<>();
//		查询当前用户的拥有的所有的权限内容
        List<Permission> list = null;
        try {
            list = permissionService.selectByUid(user.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        for (Permission permission : list) {
//			不能存放空的权限到shiro
            String url = permission.getUrl();
			if (url != null && !"".equals(url)) {
                permissions.add(url);
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);// 将权限放入shiro中.
        return info;
    }

}

添加上shiro的配置类

package com.liuxi.config;

import java.util.LinkedHashMap;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;

/**
 * - shiro的配置类
 */
@Configuration
public class ShiroConfiguration {

	//拦截的方法
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
		ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
		bean.setSecurityManager(manager);
		// 配置登录的url和登录成功的url
		bean.setLoginUrl("/toLogin");// 去登录页面的地址
		bean.setUnauthorizedUrl("/noPer");

		bean.setSuccessUrl("/index");// 登录成功之后跳转的地址

		// 配置访问权限,需要使用LinkedHashMap,因为它必须保证有序
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		//		anon:所有url都都可以匿名访问
		//		authc: 需要认证才能进行访问
		//		user:配置记住我或认证通过可以访问
		//		filterChainDefinitionMap.put("需要访问的url", "访问权限");
		filterChainDefinitionMap.put("/statics/*", "anon"); // 表示可以匿名访问
		filterChainDefinitionMap.put("/toLogin", "anon");
		filterChainDefinitionMap.put("/login", "anon");
		filterChainDefinitionMap.put("/**", "authc");// 表示需要认证才可以访问
		bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return bean;
	}

	// 配置核心安全事务管理器
	@Bean(name = "securityManager")
	public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
		System.err.println("--------------shiro已经加载----------------");
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(authRealm);
		return manager;
	}

	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
		creator.setProxyTargetClass(true);
		return creator;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			@Qualifier("securityManager") SecurityManager manager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(manager);
		return advisor;
	}
}

添加页面:

Idea Spring-boot整合shiro安全框架_第9张图片
login:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2020/07/23
  Time: 下午 4:25
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<form action="${pageContext.request.contextPath}/login">

    账户:<input type="text" name="user"><br>
    密码:<input type="password" name="pwd"><br>
    <input type="submit" value="登陆">

</form>
</body>
</html>

index功能页面添加上
导入shiro标签库<%@ taglib uri=“http://shiro.apache.org/tags” prefix=“shiro”%>
在按钮上添加,如果有权限就会显示标签内容,没有则不显示

<shiro:hasPermission name="/xxx"></shiro:hasPermission>
<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2020/07/23
  Time: 下午 1:01
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
<html>
<head>
    <title>hello</title>
</head>
<body>
欢迎您登陆,${user.username}

<shiro:hasPermission name="/insert">
    <a href="${pageContext.request.contextPath}/insert">新增</a>
</shiro:hasPermission>

<shiro:hasPermission name="/update">
    <a href="${pageContext.request.contextPath}/update">修改</a>
</shiro:hasPermission>

<shiro:hasPermission name="/delete">
    <a href="${pageContext.request.contextPath}/delete">删除</a>
</shiro:hasPermission>

<shiro:hasPermission name="/select">
    <a href="${pageContext.request.contextPath}/select">查询</a>
</shiro:hasPermission>

<a href="${pageContext.request.contextPath}/logout">登出</a>
</body>
</html>

Idea Spring-boot整合shiro安全框架_第10张图片

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2020/07/23
  Time: 下午 4:28
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
删除
</body>
</html>

IndexController编写登陆登出等等逻辑和权限控制

package com.liuxi.controller;


import com.liuxi.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@Controller
public class IndexController {

    @RequestMapping("index")
    public String index(){
        System.out.println(666);
        return "index";
    }

    @RequestMapping("login")
    public String login(String user, String pwd, ModelMap map, HttpSession session) throws Exception {
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user, pwd);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(usernamePasswordToken); // 完成登录
            User user2 = (User) subject.getPrincipal();
            session.setAttribute("user", user2);
            return "redirect:/";
        } catch (Exception e) {
            return "login";// 返回登录页面
        }
    }

    @RequestMapping("/logout")
    public String logout(HttpSession session) {
        //先remove session作用域的用户信息
        session.removeAttribute("user");
        //再shiro框架做logout操作
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/toLogin";
    }

    @RequestMapping("toLogin")
    public String toLogin(){
        System.out.println(666);
        return "login";
    }

    @RequiresPermissions("/insert")      //	@RequiresPermissions("添加权限的url")使用来添加权限的
    @RequestMapping("insert")
    public String insert(){
        return "/user/insert";
    }

    @RequiresPermissions("/update")
    @RequestMapping("update")
    public String update(){
        return "/user/update";
    }

    @RequiresPermissions("/select")
    @RequestMapping("select")
    public String select(){
        return "/user/select";
    }

    @RequiresPermissions("/delete")
    @RequestMapping("delete")
    public String delete(){
        return "/user/delete";
    }
}

效果:
Idea Spring-boot整合shiro安全框架_第11张图片
在这里插入图片描述
Idea Spring-boot整合shiro安全框架_第12张图片
在这里插入图片描述

你可能感兴趣的:(spring,boot,shiro)