今天看了一下shiro,学习了一下如何使用。
首先第一个感觉就是和spring security相比感觉很像。
因为都是安全框架,所以作用都是为了认证和授权。spring security的核心是3个重载的configure,而shiro我只是做了个小demo,很多没了解全。就目前的感觉,核心是getDefaultWebSecurityManager和getShiroFilterFactoryBean方法。
如果类比的话,getShiroFilterFactoryBean其实就是重载http请求的configure方法,里面定义了各个路径需要什么权限才能方法。
如下:
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/* *
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录)可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
Map<String,String> filterMap = new LinkedHashMap<String,String>();
filterMap.put("/add", "authc");
filterMap.put("/update", "authc");
filterMap.put("/testThymeleaf", "anon");
//放行login.html页面
filterMap.put("/login", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
//perms括号中的内容是权限的值
filterMap.put("/add", "perms[user:add]");
filterMap.put("/update", "perms[user:update]");
filterMap.put("/*", "authc");
//修改调整的登录页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
而getDefaultWebSecurityManager就是另一种重载了user-detail的configure
方法,在函数里设置是否内存读取还是数据库,若是数据库则设置user-realm(这是该框架类似的user-detail):
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
这样一看userRealm就和之前userservice依赖注入很像。
类似的写法:
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
再看userrealm的构造,很容易就联想到时要查询数据库的,这个时候和spring security就有所区别了,因为这个不是继承一个loadUserByUsername方法,而是继承了两个方法:doGetAuthenticationInfo(认证)与doGetAuthorizationInfo(鉴权),
但是实际上他们的服务内容是一致的,都是查询数据库获得用户身份与权限,只不过他将loadUserByUsername分成了两部分操作,当然,也就存入了两个对象之中,但是这并不重要,因为这两个对象都属于userRealm,其实可以理解为两种框架的实现流程都是一致的,只不过做法不同,很多小细节都不一样。
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userSerivce;
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro判断逻辑,判断用户名和密码
//1.判断用户名 token中的用户信息是登录时候传进来的
UsernamePasswordToken token = (UsernamePasswordToken)arg0;
User user = userSerivce.findByName(token.getUsername());
if(user==null){
//用户名不存在
return null;//shiro底层会抛出UnKnowAccountException
}
//2.判断密码
//第二个字段是user.getPassword(),注意这里是指从数据库中获取的password。第三个字段是realm,即当前realm的名称。
//这块对比逻辑是先对比username,但是username肯定是相等的,所以真正对比的是password。
//从这里传入的password(这里是从数据库获取的)和token(filter中登录时生成的)中的password做对比,如果相同就允许登录,
// 不相同就抛出IncorrectCredentialsException异常。
//如果认证不通过,就不会执行下面的授权方法了
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
//doGetAuthorizationInfo方法可能会执行多次,权限判断次数多少,就会执行多少次
System.out.println("执行授权逻辑1");
System.out.println("执行授权逻辑2");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
//info.addStringPermission("user:add");
//到数据库查询当前登录用户的授权字符串
//获取当前登录用户
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();
User dbUser = userSerivce.findById(user.getId());
info.addStringPermission(dbUser.getPerms());
return info;
}
}
shiro的注解使用还没了解,想必也是很相似,一通百通。