在进行web开发的过程中我们需要对特定的资源进行拦截,只有拥有相应的权限的时候才能够进行操作、访问,在这时候我们一般会想起来 拦截器与过滤器,在这里我们使用一种框架: shiro框架内置的拦截器进行拦截,shiro是apache下的安全框架,其能够进行加密、拦截、验证登录,学习成本与spring的安全框架相比成本较低,在这里我们采用Shiro框架进行相应的拦截。
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-spring-boot-web-starterartifactId>
<version>1.7.1version>
dependency>
@Configuration
public class shiroConfig {
@Bean(name = "userRealm")
public UserRealm userRealm() {
System.out.println("666666666666666");
UserRealm realm=new UserRealm();
return realm;
}
@Bean("defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(defaultWebSecurityManager);
//采用linkedHashmap->连续的
Map<String,String> map=new LinkedHashMap<>();
/*
anon 无需验证就能够访问
authc 必须任认证了才能够访问
user: 必须认证且拥有记住我才能够访问
perms 拥有某个资源权限才能够访问
role 拥有某个角色的权限才能够访问
*/
//在这里其实时进行了一系列的拦截操作,如果是大型项目可以直接/** 但是这里比较少,直接put进行添加
map.put("/login.html","anon");
map.put("/user/login","anon");
//在这里进行了角色的设置,只有角色为 1 的用户才可以访问
map.put("/user/athon","roles[1]");
map.put("/**","authc");
factoryBean.setFilterChainDefinitionMap(map);
factoryBean.setLoginUrl("/login.html");
return factoryBean;
}
}
public class UserRealm extends AuthorizingRealm {
@Resource
UserDao userDao;
//授权
@Override
//在没有进行相应的权限拦截的时候我们发现,在认证之后就不会调用这个方法 容易踩坑
//
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//拿到作用域中的数据,在认证过程中我们将user对象放了进去,现在我们可以取出来
System.out.println("============="+principals.getPrimaryPrincipal());
User user = (User) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
List<String> list=new LinkedList<>();
for (int i = 0; i < user.getVIP() + 1; i++) {
String role= String.valueOf(i);
list.add(role);
}
info.addRoles(list);
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken token1= (UsernamePasswordToken) token;
String username=token1.getUsername();
User user = userDao.findUserByName(username);
if (user == null) {
//在这里返回null后就会报错,报错为UnknownAccountException,表示账号不存在,可以直接捕捉异常
return null;
}
//密码认证在这里进行实现,如果不正确会直接报错:IncorrectCredentialsException 可以直接捕捉异常
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
}
}
Subject subject=SecurityUtils.getSubject();
if(subject.hasRole("1")){
...
}
我们使用的根据角色进行的拦截,我们要对需要拦截的方法加上一个注解@RequiresRoles
我们需要对RequiresRoles注解进行一个认识,它是基于角色进行拦截的,我们只需要输入我们需要的角色即可,同时也可以有多个角色,这时候我们分析他的源码,可以看出来他其实是一个字符串数组的形式,因此我们可以直接写一个数组,
用逗号隔开即可。
但是我们发现,在使用的时候会进行报错,500的报错说是不存在**的roles,这时候我们看底层的源码
在默认情况下,为Logical.AND,AND就很容易理解,就是必须同时满足才可以,那么如果只满足一个如何解决?我们看Logical类,发现它是一个枚举类,存在两个值:
or 就很容易理解,就是满足其中任意一个即可,因此我们可以直接使用Logical.or即可
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor=new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
将这些一并写入到配置类中即可~
带深入研究~