前言
一个简单的Spring Boot集成Shiro的demo。
1. 准备
一个Spring Boot项目。
2. 引入依赖
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.8.0</version>
</dependency>
3. 编码
3.1. 重写realm
public class CustomRealm extends AuthorizingRealm {
/**
* 盐值
*/
private static final String SALT = "as%j#Dw2";
@Resource
private UserMapper userMapper;
@Resource
private UserRoleMapper userRoleMapper;
@Resource
private RolePermissionMapper rolePermissionMapper;
// 通过principals从数据源查询用户权限数据
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
List<Role> roleInfos = userRoleMapper.selectRolesByUserId(user.getId());
List<String> roles = new ArrayList<>();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role roleInfo : roleInfos) {
roles.add(roleInfo.getCode());
info.addStringPermissions(rolePermissionMapper.selectPermissionsByRoleId(roleInfo.getId()));
}
info.addRoles(roles);
return info;
}
// 通过token从数据源查询用户身份验证数据
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
User user = userMapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getUsername, username));
if (user == null)
throw new UnknownAccountException();
return new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(SALT), this.getName());
}
}
3.2. 编写配置类
@Configuration
public class ShiroConfig {
/**
* 自定义凭证匹配器
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
// 加密方式
matcher.setHashAlgorithmName(new Md5Hash().getAlgorithmName());
// 散列迭代次数
matcher.setHashIterations(7);
return matcher;
}
/**
* realm
*/
@Bean
public Realm realm(@Autowired HashedCredentialsMatcher hashedCredentialsMatcher) {
CustomRealm realm = new CustomRealm();
// 设置凭证匹配器
realm.setCredentialsMatcher(hashedCredentialsMatcher);
return realm;
}
/**
* 请求过滤链。过滤链与注解方式同一功能的两种实现,相互独立,选其一即可。
*/
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/users", "authc, perms[user:create]");
return chainDefinition;
}
/**
* 安全管理器
*/
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(Realm realm) {
return new DefaultWebSecurityManager(realm);
}
/**
* 过滤器工厂bean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(ShiroFilterChainDefinition chainDefinition, DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
factoryBean.setSecurityManager(securityManager);
// 设置过滤链
factoryBean.setFilterChainDefinitionMap(chainDefinition.getFilterChainMap());
// 设置登录页
factoryBean.setLoginUrl("/login");
return factoryBean;
}
}
3.3. 编写功能接口
@PostMapping
// @RequiresPermissions("user:create")
public Result<?> create(@RequestBody CreateUserDTO dto) {
return userService.create(dto);
}