shiro的初步学习
shiro 是一个权限管理的框架,之前就听过,但一直没学习,寒假在家还不开学,实在玩不下去了,来学个这玩玩
快速构建
- 首先创建了一个springboot 工程
- 然后加入shiro 相关依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency>
- 创建config文件进行相关配置
- shiro中有三个重要的东西
- Subject:用户主体(关联SecurityManager,把操-作交给SecurityManager)
- SecurityManager:安全管理器(关联Realm)
- Realm:shiro连接数据库的桥梁
@Configuration
public class ShiroConfig {
/**
* 创建 ShiroFilterFactoryBean
*/
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*
* shiro中securityManager用来管来 Realm
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
//创建管理类
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
*
*
* 可以自定义Realm类
*/
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
- 创建 realm
public class UserRealm extends AuthorizingRealm {
/**
* 执行授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
return null;
}
}
这个时候进入html页面进行访问是可以的,但是如果ShiroFilterFactoryBean没有加入@Bean注解的话,无论你url怎么写,都会跳转到login.jsp页面,如果出现这种情况,记得检查自己的配置文件。
简单的认证管理
新建user 的add.html 和 update.html
然后在 controller 里面(或者在webConfig下配置也可以)进行相关配置
在index.html中使用超链接指向 这两个文件
这个时候是可以进入的,因为我们还没在ShiroConfig中还没添加 Shiro内置的过滤器
- 常用的过滤器
- anon: 无需认证(登录) 就可以访问
- authc: 必须认证才可以访问
- user: rememberMe(记住我) 后才可以访问
- role: 该资源必须得到角色权限才可以访问
- perms: 该资源必须得到资源权限才可以访问
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加shiro的内置过滤器
/**
* shiro内置过滤器
* 用来对 url 拦截
*/
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/add","authc");
filterMap.put("/update","authc");
//调整登录页面,默认情况下为login.jsp
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
这个时候再访问 /add.html,/update.html 就会发现自动重定向到了 login.html
如果需要登录验证的话 修改Realm
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
User user = userService.findUser(token.getUsername());
if (user == null){
//如果返回 null shiro会帮我们抛出一个 UnknownAccountException
//也就是用户不存在
return null;
}
//判断密码
//SimpleAuthenticationInfo 是 AuthenticationInfo的子类
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
简单的授权管理
有的时候我们需要对特定资源进行授权,当登录的用户有这个权限的时候才允许访问。
比如说现在有个需求是
两个账户halo和tu
halo拥有insert权限
tu拥有update权限
这个时候我们需要在过滤器对 url 添加所对应的权限
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/add","authc");
filterMap.put("/update","authc");
//调整登录页面
shiroFilterFactoryBean.setLoginUrl("/login");
//授权过滤器
filterMap.put("/add","perms[user:add]");
filterMap.put("/update","perms[user:update]");
//设置未授权的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
然后在Realm中编写 认证逻辑
注意:
如果你要通过 subject.getPrincipal() 来获取当前登录的用户的话,你需要在 doGetAuthenticationInfo方法中最后修改成
第一个参数就是你要返回的值
第二个参数用来验证密码
return new SimpleAuthenticationInfo(user,user.getPassword(),””);
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//对 user:add 进行授权
// info.addStringPermission("user:add");
//获取当前登录的用户
//其实我觉得这步没必要,又去数据库查了,较好的做法应该在登录的时候就一次性拿出权限
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
info.addStringPermission(user.getPerms());
return info;
}
如果没有权限的话,会跳转到setUnauthorizedUrl()设置的 url