数据表user:
权限perm表:
maven配置:
<?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.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.ping</groupId>
<artifactId>shiro-springboot</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>shiro-springboot</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.5.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.20</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8081
spring:
application:
name: shiro-springboot
datasource:
username: root
password: 123456
#?serverTimezone解决时区的报错
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&Unicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#Spring boot 默认不注入这些属性值,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 6000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters , stat 监控统计,log4j 日志记录,wall:防御slq注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.priority
#则导入log4j 依赖即可
filters: stat,wall,log4j
maxPoolPrepareStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis:
type-aliases-package: cn.ping.shirospringboot.pojo
mapper-locations: classpath:mapper/*.xml
logging:
level:
cn:
ping:
shirospringboot: trace
实体类User:
package cn.ping.shirospringboot.pojo;
public class User {
private int id;
private String name;
private String password;
private String salt;
public User(int id, String name, String password,String salt) {
this.id = id;
this.name = name;
this.password = password;
this.salt = salt;
}
public User() {}
}
shiroCofig配置类:
package cn.ping.shirospringboot.config;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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;
import java.util.LinkedHashMap;
@Configuration
public class ShiroConfig {
//shiroFilterFactoryBean :3
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* anon:无需认证就可以访问
* authc : 必须认证成功
* user: 必须拥有记住我功能才能用
* perms: 拥有对某个资源的权限才能访问
* role:拥有某个角色权限才能访问
*/
//拦截
LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();
//添加授权拦截
filterMap.put("/user/add","perms[add]");
filterMap.put("/user/update","perms[update]");
//添加认证拦截
filterMap.put("/user/*","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//没有授权的跳转页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
return shiroFilterFactoryBean;
}
//DefaultWebSecurityManager: 2
@Bean(name = "securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象,需要自定义类 :1
@Bean
public UserRealm userRealm(){
UserRealm realm = new UserRealm();
//设置realm使用hash凭证匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//使用md5算法
credentialsMatcher.setHashAlgorithmName("md5");
//散列次数
credentialsMatcher.setHashIterations(1024);
realm.setCredentialsMatcher(credentialsMatcher);
return realm;
}
}
自定义Realm类
package cn.ping.shirospringboot.config;
import cn.ping.shirospringboot.pojo.User;
import cn.ping.shirospringboot.server.IPermService;
import cn.ping.shirospringboot.server.IUserService;
import org.apache.shiro.SecurityUtils;
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.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.List;
public class UserRealm extends AuthorizingRealm {
@Autowired
private IUserService iUserService;
@Autowired
private IPermService iPermService;
/*@Value("${cn.ping.slat}")
private String slat;*/
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取当前用户的信息,必须用到认证通过用户的信息,所以认证方法要将用户信息设置给shiro
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();//获得用户信息,通过用户id来获取权限表的权限信息
List<String> permList = iPermService.queryPermsByUserId(user.getId());
//添加授权认证
authorizationInfo.setStringPermissions(new HashSet(permList));
//authorizationInfo.addStringPermission("add");
return authorizationInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthenticationInfo");
/*String userName = "admin";
String password = "123";*/
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
//通过用户名获取用户
User user = iUserService.queryUserByName(userToken.getUsername());
//如果user为Null,则用户不存在
if (user == null){
return null; //抛出异常 UnknownAccountException
}
//密码认证 ,shiro自己会完成,参数1把用户信息传给shiro
return new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),"myRealm");
}
}
生成随机盐值和md5密码的工具类:
package cn.ping.shirospringboot.utils;
import org.apache.shiro.crypto.hash.Md5Hash;
public class Md5Utils {
//随机盐值
public static final char[] salts = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/**
* 获取随机的盐值
*/
public static String getSalt(){
StringBuilder salt = new StringBuilder();
for (int i = 0; i < 4; i++) {
salt.append(salts[(int) ((Math.random() * 16))]);
}
return salt.toString();
}
/**
* 获取md5的密码
* @param password
* @return
*/
public static String getMd5Password(String password,String salt){
Md5Hash md5Hash2 = new Md5Hash(password, salt, 1024);
return md5Hash2.toHex();
}
}
demo代码地址:https://download.csdn.net/download/qq_20768305/29718735