一、流程图
ShiroFilter会拦截用户发来的所有请求,然后判断该请求是否需要做认证和授权,也就是判断该请求访问的是受限资源还是公共资源,访问受限资源的话就要做认证和授权,利用SecurityManager、Realm做认证、授权,认证失败跳转到登录页,访问公共资源的话直接放行
二、shiro中的过滤器
三、整合步骤
1.引入shiro依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.5.3</version>
</dependency>
2.创建自定义Realm类
这里面完成认证和授权相关业务
package com.szhedu.springboot_shiro.shiro.realms;
import com.szhedu.springboot_shiro.mapper.UserMapper;
import com.szhedu.springboot_shiro.pojo.User;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Objects;
/**
* 自定义的realm
*/
public class CustomerRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRole("admin");
authorizationInfo.addStringPermission("user:add:*");
return authorizationInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String principal = (String) authenticationToken.getPrincipal();
//查询数据库,如果用户名和密码都校验成功,则认证通过
User user = userMapper.getUser(principal);
if(!Objects.isNull(user)){
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
principal,
user.getPassword(),
//盐
ByteSource.Util.bytes(user.getSalt()),
this.getName());
return authenticationInfo;
}
return null;
}
}
3.编写shiro配置类,包含三步①创建ShiroFilter②创建全局安全管理器③创建自定义Realm
package com.szhedu.springboot_shiro.config;
import com.szhedu.springboot_shiro.shiro.realms.CustomerRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* shiro配置类
*/
@Configuration
public class ShiroConfig {
//1.创建ShiroFilter
@Bean
public ShiroFilterFactoryBean getShiroFilter(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
//todo 1. 将全局安全管理器注入
shiroFilter.setSecurityManager(defaultWebSecurityManager);
//todo 2.设置受限资源
Map<String, String> map = new HashMap<>();
//公共资源先放开
map.put("/user/login","anon");
map.put("/user/register","anon");
map.put("/register.jsp","anon");
//authc表示这个资源需要认证和授权,如果没认证成功默认回到login.jsp
map.put("/**","authc");
shiroFilter.setFilterChainDefinitionMap(map);
return shiroFilter;
}
//2.创建全局安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//将自定义的realm设置到全局安全管理器中
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
//3.创建自定义Realm
@Bean
public Realm getRealm(){
CustomerRealm customerRealm = new CustomerRealm();
//todo 修改凭证校验匹配器
//这里,就会先对用户输入的密码进行MD5加密,然后再用加密后的密码去和数据库中的密码做equals判断
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//使用的算法
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列的次数
hashedCredentialsMatcher.setHashIterations(1024);
customerRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return customerRealm;
}
}
4.登录接口(认证)
//登录
@PostMapping("/user/login")
public String login(String username,String password){
Subject subject = SecurityUtils.getSubject();
try {
//会调用我们自定义的realm类进行认证和授权
subject.login(new UsernamePasswordToken(username,password));
return "redirect:/index.jsp";
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误");
}
return "redirect:/login.jsp";
}
5.授权:从数据库查询登陆用户的角色信息和所具有的权限信息,封装到SimpleAuthorizationInfo对象中返回
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
List<Role> roles = userMapper.getRoles(primaryPrincipal);
if (roles != null){
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
roles.stream().forEach(
role -> {
//封装角色信息
authorizationInfo.addRole(role.getName());
//封装权限信息
List<Perms> perms = userMapper.getPerms(role.getId());
perms.forEach(
perm -> {
authorizationInfo.addStringPermission(perm.getName());
}
);
}
);
return authorizationInfo;
}
return null;
}