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

pom.xml:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.liuxi</groupId><artifactId>spring-boot-shiro</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-shiro</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><!--排除器--><exclusions><!--排除logging--><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!-- log4j. --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j</artifactId><version>1.3.8.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.1.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>3.7.5</version></dependency><!--引入web配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- servlet依赖. --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><scope>provided</scope></dependency><!-- JSTL --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><!-- tomcat的支持. --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><!--<scope>provided</scope> --></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional><!-- optional=true,依赖不会传递,该项目依赖devtools;之后依赖myboot项目的项目如果想要使用devtools,需要重新引入 --></dependency><!-- spring aop支持 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>4.3.12.RELEASE</version></dependency><!-- aspectj支持 注解的依赖 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version></dependency><!-- druid 连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- shiro spring. --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.2.2</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.2.2</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

整合mybatis:

添加依赖
yml配置:

server:port: 8080servlet:  #启动jsp支持init-parameters:development: truecontextPath: /spssm
spring:mvc:view:prefix: /WEB-INF/page/suffix: .jspdatasource:url: jdbc:mysql://*:3306/*?useUnicode=true&characterEncoding=utf-8username: rootpassword: *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%nlog4j.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*/@Beanpublic 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*/@Beanpublic FilterRegistrationBean druidStatFilter() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());// 添加过滤规则.filterRegistrationBean.addUrlPatterns("/*");// 添加不需要忽略的格式信息.filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");return filterRegistrationBean;}
}

整合事务:

添加依赖
在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());}/*** 切面拦截规则 参数会自动从容器中注入*/@Beanpublic 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%nlog4j.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:

index.jsp:

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

访问:http://127.0.0.1:8080/spssm/index

数据库建表:

数据库有用户(user)、角色(role)、权限(permission)三个实体,除了实体表以外,为了实现表间用户与角色、角色与权限多对多的表间关系,所以产生了user_role、role_permission两张关系表。在下图中,使用红线将表的外键标记了出来,但为了方便并没有在表中创建外键,我们手动进行维护。
参考:

user:

role:

permission:

user_role:

role_permission:

编写sql语句:根据用户id查询出对应的权限:

SELECT DISTINCT*
FROMpermission
WHEREid IN (SELECTrp.pidFROMUSER uLEFT JOIN user_role ur ON u.id = ur.uidLEFT JOIN role_permission rp ON ur.rid = rp.ridWHEREu.id = 1)

结果:

生成实体类,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 {@Autowiredprivate UserMapper userMapper;@Overridepublic int deleteByPrimaryKey(Integer id) throws Exception {return userMapper.deleteByPrimaryKey(id);}@Overridepublic int insert(User record) throws Exception {return userMapper.insert(record);}@Overridepublic int insertSelective(User record) throws Exception {return userMapper.insertSelective(record);}@Overridepublic User selectByPrimaryKey(Integer id) throws Exception {return userMapper.selectByPrimaryKey(id);}@Overridepublic int updateByPrimaryKeySelective(User record) throws Exception {return userMapper.updateByPrimaryKeySelective(record);}@Overridepublic int updateByPrimaryKey(User record) throws Exception {return userMapper.updateByPrimaryKey(record);}@Overridepublic 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 {@Autowiredprivate PermissionMapper permissionMapper;@Overridepublic int deleteByPrimaryKey(Integer id) throws Exception {return permissionMapper.deleteByPrimaryKey(id);}@Overridepublic int insert(Permission record) throws Exception {return permissionMapper.insert(record);}@Overridepublic int insertSelective(Permission record) throws Exception {return permissionMapper.insertSelective(record);}@Overridepublic Permission selectByPrimaryKey(Integer id) throws Exception {return permissionMapper.selectByPrimaryKey(id);}@Overridepublic int updateByPrimaryKeySelective(Permission record) throws Exception {return permissionMapper.updateByPrimaryKeySelective(record);}@Overridepublic int updateByPrimaryKey(Permission record) throws Exception {return permissionMapper.updateByPrimaryKey(record);}@Overridepublic 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*FROMpermissionWHEREid IN (SELECTrp.pidFROMUSER uLEFT JOIN user_role ur ON u.id = ur.uidLEFT JOIN role_permission rp ON ur.rid = rp.ridWHEREu.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 {@Autowiredprivate UserService userService;@Autowiredprivate PermissionService permissionService;// 认证.登录@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {User user = null;try {UsernamePasswordToken utoken = (UsernamePasswordToken) token;// 获取用户输入的tokenString username = utoken.getUsername();user = userService.selectByName(username);} catch (Exception e) {e.printStackTrace();}return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());// 放入shiro.调用CredentialsMatcher检验密码}// 授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {User user = (User) principal.fromRealm(this.getClass().getName()).iterator().next();// 获取session中的用户// 当前用户在系统上有什么权限,把拥有的权限设置到permissionsList<String> permissions = new ArrayList<>();
//      查询当前用户的拥有的所有的权限内容List<Permission> list = null;try {list = permissionService.selectByUid(user.getId());} catch (Exception e) {e.printStackTrace();}for (Permission permission : list) {
//          不能存放空的权限到shiroString 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和登录成功的urlbean.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;}@Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();creator.setProxyTargetClass(true);return creator;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(manager);return advisor;}
}

添加页面:


login:

<%--Created by IntelliJ IDEA.User: adminDate: 2020/07/23Time: 下午 4:25To 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: adminDate: 2020/07/23Time: 下午 1:01To 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>

<%--Created by IntelliJ IDEA.User: adminDate: 2020/07/23Time: 下午 4:28To 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安全框架相关推荐

  1. Spring Boot整合Shiro + Springboot +vue

    目录 02 Spring Boot整合Shiro p1.shiro概述 1 什么是Shiro 2 Shiro核心组件 p2.Shiro实现登录认证 AccountRealm.java QueryWra ...

  2. Spring Boot 整合 shiro 之盐值加密认证详解(六)

    Spring Boot 整合 shiro 之盐值加密认证详解 概述 不加盐认证 加入密码认证核心代码 修改 CustomRealm 新增获取密文的方法 修改 doGetAuthenticationIn ...

  3. Spring Boot 整合 Shiro(三)Kaptcha验证码 附源码

    前言 本文是根据上篇<Spring Boot 整合Shiro(二)加密登录与密码加盐处理>进行修改,如有不明白的转上篇文章了解. 1.导入依赖 <!-- https://mvnrep ...

  4. 六、Spring Boot整合Shiro

    六.Spring Boot整合Shiro 6.1.整合思路 6.2.创建spring boot项目 6.3.引入shiro依赖 6.4.配置shiro环境 创建配置类ShiroConfig 1.配置: ...

  5. Spring Boot整合Shiro + JSP教程(用户认证,权限管理,图片验证码)

    在此首先感谢**编程不良人**up主提供的视频教程 代码都是跟着up的视频敲的,遇到的一些问题也是通过CSDN博主提供的教程解决的,在此也感谢那些提供bug解决方案的前辈们~ 项目完整代码已经发布到g ...

  6. spring boot整合shiro继承redis_Springboot+Shiro+redis整合

    1.Shiro是Apache下的一个开源项目,我们称之为Apache Shiro.它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与spring Security 一样都是 ...

  7. spring boot整合shiro+jjwt

    前言 本篇文章将教大家在 shiro + springBoot 的基础上整合 JJWT (JSON Web Token) JWT JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允 ...

  8. spring boot整合Shiro实现单点登录

    默认情况下,Shiro已经为我们实现了和Cas的集成,我们加入集成的一些配置就ok了 1.加入shiro-cas包 <!-- shiro整合cas单点 --><dependency& ...

  9. Spring Boot 整合 Shiro

    虽然,直接用Spring Security和SpringBoot 进行"全家桶式"的合作是最好不过的,但现实总是欺负我们这些没办法决定架构类型的娃子. Apache Shiro 也 ...

  10. spring boot整合shiro继承redis_spring-boot-plus集成Shiro+JWT权限管理

    SpringBoot+Shiro+JWT权限管理 Shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理. 使用Shiro的易于理解的API,您可以 ...

最新文章

  1. 算法--------删除重复元素,但保留两个
  2. c++ cuda拷贝内存
  3. 用access做考场桌贴_利用Word、Excel、Access进行考务安排及学生成绩分析的有效途径-教育文档...
  4. Delphi中的容器类
  5. 文件得编码和文件名的编码是不一样的
  6. WSL1 升级为 WSL2
  7. [转载]Validation of viewstate MAC failed异常的原因及解决方法
  8. 创业者没有周末,但有周期
  9. MySQL数据库学习2 - 数据库的操作
  10. matlab符号函数与对其的常用操作
  11. window10刷新卡顿
  12. Linux基础命令的那些事儿(1)
  13. C个java都是多线程语言对吗_Java里的多线程
  14. Android 9 Pie
  15. Microsoft Visual Studio 2019 美化之——透明化窗口 Microsoft Visual Studio 2019 C/C++ Windows 下重量级编辑器 Editor
  16. NOI2010~NOI2018选做
  17. PYQT5 打包后无法显示jpg图片问题
  18. 酒吧类型与其娱乐项目设置
  19. C 语言 结构体_finddata_t _findfirst, _findnext, _findclose 函数讲解
  20. Redis(上)基础及8种数据类型

热门文章

  1. 判别式模型与生成式模型的区别
  2. MATLAB 数学应用 微分方程 边界值问题 求解具有未知参数的BVP
  3. 海康、大华IpCamera摄像机 RTSP地址和格式
  4. 全球最赚钱的量化对冲基金大佬,一览量化大佬的传奇故事
  5. 天空卫士杨明非:数据驱动安全,技术智慧赋能
  6. 【LDF】线性判别函数(三)
  7. 销售和程序员哪个好_杀了程序员祭天
  8. 计算机等级证书有几级?含金量
  9. Android中的羊角符
  10. 解决高度塌陷的六种方法以及Grid网页布局补充