1分钟学会SpringBoot2知识点,让你35岁不再失业(六)
第二十四节、springboot 权限管理框架shiro
1、shiro简介
shiro是apache的一个开源框架,而且呢是一个权限管理的框架,用于实现用户认证、用户授权。spring 中也有一个权限框架 spring
security (原名Acegi),它和 spring 依赖过于紧密,没有 shiro 使用简单。shiro 不依赖于 spring,shiro 不仅可以实现 web应用的权限
管理,还可以实现c/s系统,分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。使用shiro实现系统的权限
管理,有效提高开发效率,从而降低开发成本。
2、shrio基本框架
3、认证流程
- 构建SecurityManager环境
- 主体提交认证
- SecurityManager 处理
- 流转到 Authenticator 执行认证
- 通过 Realm 获取相关的用户信息(获取验证数据进行验证)
4、授权流程
- 创建构建SecurityManager环境
- 主体提交授权认证
- SecurityManager 处理
- 流转到 Authorizor 授权器执行授权认证
- 通过 Realm 从数据库或配置文件获取角色权限数据返回给授权器,进行授权。
4、shiro项目构建
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.2.8.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.unionpay.springboot</groupId>
<artifactId>shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shiro</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
创建ShiroApplicationTests 类
package com.unionpay.springboot.shiro;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ShiroApplicationTests {
/*
用户认证
1. 构建SecurityManager环境
2. 主体提交认证
3. SecurityManager 处理
4. 流转到 Authenticator 执行认证
5. 通过 Realm 获取相关的用户信息(获取验证数据进行验证)
*/
@Test
public void authentication() {
//1、 构建一个安全管理器环境
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
simpleAccountRealm.addAccount("yyliu", "123456");
defaultWebSecurityManager.setRealm(simpleAccountRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
//2、主体提交认证
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("yyliu", "1234567");
//3. SecurityManager 处理
try {
subject.login(usernamePasswordToken);
System.out.println("用户认证的状态:" + subject.isAuthenticated());
subject.logout();//退出
System.out.println("用户认证的状态:" + subject.isAuthenticated());
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}
}
/*用户授权
1. 构建SecurityManager环境
2. 主体提交授权认证
3. SecurityManager 处理
4. 流转到 Authorizor 授权器执行授权认证
5. 通过 Realm 从数据库或配置文件获取角色权限数据返回给授权器,进行授权。
*/
@Test
public void authorization() {
//1. 构建SecurityManager环
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
simpleAccountRealm.addAccount("zhangsan", "666666","admin","test");
defaultWebSecurityManager.setRealm(simpleAccountRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
//2、 主体提交授权认证
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zhangsan", "666666");
//3. SecurityManager 处理
try {
subject.login(usernamePasswordToken);
System.out.println("用户授权的状态:" + subject.isAuthenticated());
// subject.checkRoles("admin","test");
subject.checkRoles("test");
subject.logout();
System.out.println("用户授权的状态:" + subject.isAuthenticated());
//if no exception, that's it, we're done!
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}catch (UnauthorizedException e){
System.out.println("该用户没有权限访问");
}
}
//通过配置文件的方式去读取保存的权限
@Test
public void testIniRealm(){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
//classpath为自己建的文件
IniRealm iniRealm=new IniRealm("classpath:shiro.ini");
defaultWebSecurityManager.setRealm(iniRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "123456");
try {
subject.login(usernamePasswordToken);
System.out.println("用户认证的状态" + subject.isAuthenticated());
subject.checkRoles("admin");
subject.checkPermissions("user:deleted","role:list");
subject.logout();
System.out.println("用户认证的状态" + subject.isAuthenticated());
//if no exception, that's it, we're done!
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}catch (UnauthorizedException e){
System.out.println("该用户没有权限访问");
}
}
/**
* 通过mysql的方式保存权限
*/
@Test
public void testJdbcRealm(){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
JdbcRealm jdbcRealm=new JdbcRealm();
//jdbc数据源添加
DruidDataSource druidDataSource=new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://localhost:3306/shiro?useSSL=false");
druidDataSource.setUsername("root");
druidDataSource.setPassword("6415772");
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
jdbcRealm.setPermissionsLookupEnabled(true);
String authenticationQuery = "select password from users where username = ?";
String userRolesQuery = "select role_name from user_roles where username = ?";
String permissionsQuery = "select permission from roles_permissions where role_name = ?";
jdbcRealm.setAuthenticationQuery(authenticationQuery);
jdbcRealm.setUserRolesQuery(userRolesQuery);
jdbcRealm.setPermissionsQuery(permissionsQuery);
jdbcRealm.setDataSource(druidDataSource);
defaultWebSecurityManager.setRealm(jdbcRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("test", "123456");
try {
subject.login(usernamePasswordToken);
System.out.println("用户认证的状态" + subject.isAuthenticated());
subject.checkRoles("test");
subject.checkPermissions("user:deleted","user:list");
subject.logout();
System.out.println("用户认证的状态" + subject.isAuthenticated());
//if no exception, that's it, we're done!
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}catch (UnauthorizedException e){
System.out.println("该用户没有权限访问");
}
}
/**
* 自定义Realm进行认证授权
*/
@Test
public void testCustomRealm(){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
CustomRealm customRealm=new CustomRealm();
defaultWebSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "123456");
try {
subject.login(usernamePasswordToken);
System.out.println("用户认证的状态" + subject.isAuthenticated());
subject.checkRoles("test");
subject.checkPermissions("user:deleted","user:list","role:list");
subject.logout();
System.out.println("用户认证的状态" + subject.isAuthenticated());
//if no exception, that's it, we're done!
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}catch (UnauthorizedException e){
System.out.println("该用户没有权限访问");
}
}
/**
* 不加盐加密详细认证
*/
@Test
public void testMatcher(){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
CustomRealm customRealm=new CustomRealm();
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
matcher.setHashIterations(3);
customRealm.setCredentialsMatcher(matcher);
defaultWebSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "123456");
try {
subject.login(usernamePasswordToken);
System.out.println("用户认证的状态" + subject.isAuthenticated());
subject.checkRoles("test");
subject.checkPermissions("user:deleted","user:list","role:list");
subject.logout();
System.out.println("用户认证的状态" + subject.isAuthenticated());
//if no exception, that's it, we're done!
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}catch (UnauthorizedException e){
System.out.println("该用户没有权限访问");
}
}
/**
* 加盐加密详细认证
*/
@Test
public void testSaltMatcher(){
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
CustomRealm customRealm=new CustomRealm();
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
//这里的次数要匹配
matcher.setHashIterations(3);
customRealm.setCredentialsMatcher(matcher);
defaultWebSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultWebSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "123456");
try {
subject.login(usernamePasswordToken);
System.out.println("用户认证的状态" + subject.isAuthenticated());
subject.checkRoles("test");
subject.checkPermissions("user:deleted","user:list","role:list");
subject.logout();
System.out.println("用户认证的状态" + subject.isAuthenticated());
//if no exception, that's it, we're done!
} catch (UnknownAccountException uae) {
System.out.println("用户不存在");
} catch (IncorrectCredentialsException ice) {
System.out.println("用户密码不匹配");
} catch (LockedAccountException lae) {
System.out.println("账号已被锁定");
} catch (AuthenticationException ae) {
System.out.println("用户认证异常");
}catch (UnauthorizedException e){
System.out.println("该用户没有权限访问");
}
}
}
创建CustomRealm类
package com.unionpay.springboot.shiro;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 刘阳洋
* @date 2020/5/20 20:13
*/
public class CustomRealm extends AuthorizingRealm {
/**
* mock 用户信息
* @param principalCollection
* @return
*/
private Map<String,String> userMap=new HashMap<>();
{
userMap.put("admin","123456");
userMap.put("test","123456");
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username= (String) principalCollection.getPrimaryPrincipal();
List<String> roles=getRolesByUserName(username);
List<String> permissions=getPermissionsByUsername(username);
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = (String) authenticationToken.getPrincipal();
String password=getPasswordByUsername(username);
if(StringUtils.isEmpty(password)){
return null;
}
// SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(username,password,getName());
// SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(username,getEncPassword(password),getName());
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(username,getEncPassword(password,username),getName());
info.setCredentialsSalt(ByteSource.Util.bytes(username));
return info;
}
// private String getEncPassword(String password){
// return new Md5Hash(password,null,3).toString();
// }
private String getEncPassword(String password,String salt){
return new Md5Hash(password,salt,3).toString();
}
/**
* 通过用户名获取密码
* @Author: 刘阳洋
* @UpdateUser:
* @Version: 0.0.1
* @param username
* @return java.lang.String
* @throws
*/
private String getPasswordByUsername(String username){
return userMap.get(username);
}
/**
* 通过用户名获取用户拥有角色信息
* @Author:
* @UpdateUser:
* @Version: 0.0.1
* @param username
* @return java.util.List<java.lang.String>
* @throws
*/
private List<String> getRolesByUserName(String username){
List<String> roles=new ArrayList<>();
if(username.equals("admin")){
roles.add("admin");
}
roles.add("test");
return roles;
}
/**
* 通过用户名获取用户拥有权限信息
* @Author:
* @UpdateUser:
* @Version: 0.0.1
* @param username
* @return java.util.List<java.lang.String>
* @throws
*/
private List<String> getPermissionsByUsername(String username){
List<String> permissions=new ArrayList<>();
if(username.equals("admin")){
permissions.add("*");
}
permissions.add("user:list");
permissions.add("user:deleted");
permissions.add("user:edit");
return permissions;
}
}
创建sql语句
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(25) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(25) DEFAULT NULL,
`username` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `roles_permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`permission` varchar(255) DEFAULT NULL,
`role_name` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `shiro`.`users` (`id`, `username`, `password`) VALUES ('1', 'admin', '123456');
INSERT INTO `shiro`.`users` (`id`, `username`, `password`) VALUES ('2', 'test', '123456');
INSERT INTO `shiro`.`user_roles` (`id`, `role_name`, `username`) VALUES ('1', 'admin', 'admin');
INSERT INTO `shiro`.`user_roles` (`id`, `role_name`, `username`) VALUES ('2', 'test', 'test');
INSERT INTO `shiro`.`roles_permissions` (`id`, `permission`, `role_name`) VALUES ('1',
'user:deleted', 'test');
INSERT INTO `shiro`.`roles_permissions` (`id`, `permission`, `role_name`) VALUES ('2',
'user:list', 'test');
INSERT INTO `shiro`.`roles_permissions` (`id`, `permission`, `role_name`) VALUES ('3', '*',
'admin');
INSERT INTO `shiro`.`roles_permissions` (`id`, `permission`, `role_name`) VALUES ('4',
'user:edit', 'test');
创建shiro.ini
[users]
test=123456,test
admin=123456,admin
[roles]
test=user:list,user:edit
admin=*
启动类
package com.unionpay.springboot.shiro;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ShiroApplication {
public static void main(String[] args) {
SpringApplication.run(ShiroApplication.class, args);
}
}