一、Shiro结构
shiro主要有三大功能模块:
1. Subject:主体,一般指用户。
2. SecurityManager:安全管理器,管理所有Subject,可以配合内部安全组件。(类似于SpringMVC中的DispatcherServlet)
3. Realms:用于进行权限信息的验证,一般需要自己实现。
二、使用实例
1、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.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mytest_springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mytest_springboot</name>
<description>mytest_springboot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、创建涉及到的实体类
a.User
@Data
@AllArgsConstructor
public class User {
private String id;
private String userName;
private String password;
private Set<Role> roles;
}
b.Role
@Data
@AllArgsConstructor
public class Role {
private String id;
private String roleName;
private Set<Permissions> permissions;
}
c.Permissions
@Data
@AllArgsConstructor
public class Permissions {
private String id;
private String permissionsName;
}
3、模拟数据库信息
public interface LoginService {
User getUserByName(String getMapByName);
}
@Service
public class LoginServiceImpl implements LoginService {
@Override
public User getUserByName(String getMapByName) {
return getMapByName(getMapByName);
}
/**
* 模拟数据库查询
*
* @param userName 用户名
* @return User
*/
private static User getMapByName(String userName) {
Permissions permissions1 = new Permissions("1", "add");
Permissions permissions2 = new Permissions("2", "delete");
Set<Permissions> permissionsSet = new HashSet<>();
permissionsSet.add(permissions1);
permissionsSet.add(permissions2);
Role role = new Role("1", "select", permissionsSet);
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
User user = new User("1", "lsl", "123456", roleSet);
Map<String, User> map = new HashMap<>();
map.put(user.getUserName(), user);
Set<Permissions> permissionsSet1 = new HashSet<>();
permissionsSet1.add(permissions1);
Role role1 = new Role("2", "query", permissionsSet1);
Set<Role> roleSet1 = new HashSet<>();
roleSet1.add(role1);
User user1 = new User("2", "lcz", "123456", roleSet1);
map.put(user1.getUserName(), user1);
return map.get(userName);
}
}
4、自定义Realm
public class MyRealm extends AuthorizingRealm {
@Resource
private LoginService loginService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
String userName = (String) principal.getPrimaryPrincipal();
User user = loginService.getUserByName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
simpleAuthorizationInfo.addRole(role.getRoleName());
for (Permissions permission : role.getPermissions()) {
simpleAuthorizationInfo.addStringPermission(permission.getPermissionsName());
}
}
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
if (StringUtils.isEmpty(authenticationToken.getPrincipal())) {
return null;
}
String userName = authenticationToken.getPrincipal().toString();
User user = loginService.getUserByName(userName);
if (Objects.isNull(user)) {
return null;
}
return new SimpleAuthenticationInfo(userName, user.getPassword(), getName());
}
}
5、配置ShiroConfig
@Configuration
public class ShiroConfig {
//自动代理创建者
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public MyRealm myRealm() {
return new MyRealm();
}
//主要是Realm的管理认证
//注:DefaultWebSecurityManager 不是DefaultSecurityManager
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
defaultSecurityManager.setRealm(myRealm());
return defaultSecurityManager;
}
//配置过滤放开跳转条件
//anon:放开 、authc:认证
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
map.put("/one", "anon");
map.put("/two", "authc");
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/success");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//开启代码权限注解支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
6.测试
@RestController
@Slf4j
public class ShiroController {
@PostMapping("/test/shiro")
public String login(@RequestBody User user) {
if (Objects.isNull(user.getUserName()) || Objects.isNull(user.getPassword())) {
return "请输入用户名和密码";
}
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUserName(), user.getPassword());
try {
subject.login(usernamePasswordToken);
} catch (UnknownAccountException e) {
log.error("用户不存在!");
return "用户不存在!";
} catch (AuthenticationException e) {
log.error("账号或密码错误");
return "账号或密码错误";
} catch (AuthorizationException e) {
log.error("没有权限");
return "没有权限";
}
return "登录成功";
}
@RequiresRoles("user")
@PostMapping("/test/add")
public String admin() {
return "添加成功";
}
@RequiresPermissions("query")
@PostMapping("/test/delete")
public String delete() {
return "删除成功";
}
}