赞
踩
1) 获取ShiroFilterFactoryBean,作用是在执行相关操作前,先进行功能过滤,拦截所有请求,进入到shiro中进行认证与授权
例如:设置一些拦截的请求
// 身份认证失败,则跳转到登录页面的配置
bean.setLoginUrl(“/tologin”);
// 权限认证失败,则跳转到指定页面
bean.setUnauthorizedUrl(“/tologin”);
2) 创建SecurityManager,来管理shiro;Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
3) Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息,可见Realm的重要。
当配置 Shiro时,你必须至少指定一个 Realm ,用于认证和(或)授权。配置多个 Realm 是可以的,但是至少需要一个。
Shiro默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm,以userRealm为例子。
shiroConfig配置:
package com.example.demo.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/* // 身份认证失败,则跳转到登录页面的配置
bean.setLoginUrl("/tologin");
// 权限认证失败,则跳转到指定页面
bean.setUnauthorizedUrl("/tologin");*/
//添加shiro的内置过滤器
/**
* anno 无需认证就可以访问必须认证了才能访问
*authc
* user:必须拥有记住我功能才适用
* perms :拥有对某个资源的权限才能访问
* role:拥有某个角色的权限
*/
//拦截请求
// Map<String,String> filterChainDefinitionMap =new LinkedHashMap<>();
// filterChainDefinitionMap.put("/tologin","authc");//免登录验证
// filterChainDefinitionMap.put("/user/update","anon");//免登录验证
// filterChainDefinitionMap.put("/user/**","authc");//支持通配符操作 authc
// filterChainDefinitionMap.put("/user/add","authc");//身份验证
//方式一:anon,authc
Map<String,String> filterChainDefinitionMap =new LinkedHashMap<>();
filterChainDefinitionMap.put("/user/add","anon");
filterChainDefinitionMap.put("/user/update","authc");
// filterChainDefinitionMap.put("/**","authc");//支持通配符操作 authc
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
/*
//方式二:perms
Map<String,String> filterMap =new LinkedHashMap<>();
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
bean.setFilterChainDefinitionMap(filterMap);*/
//方式三:roles 加上roleFilter 类,并在UserRealm增加info.addRole("user");
/*Map<String,String> filterMap =new LinkedHashMap<>();
filterMap.put("/user/add","roles[user]");
filterMap.put("/user/update","roles[leader]");
bean.setFilterChainDefinitionMap(filterMap);*/
bean.setLoginUrl("/tologin");
//设置未授权的请求
bean.setUnauthorizedUrl("/noauth");
return bean;
}
//方式二:user
/*
登录接口加上 token.setRememberMe(true);
<shiro:user>
当有记住我信息,或已登录,则显示标签体内容
</shiro:user>
*/
//DefaultWebSecurityManager2
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
//关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象,需要自定义类1
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合shiroDialect:用来整合shiro thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
userRealm配置
package com.example.demo.config;
import com.example.demo.pojo.User;
import com.example.demo.service.imp.UserServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm {
@Autowired
UserServiceImpl userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权");
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
// info.addRole("user");
info.addStringPermission("user:update");
info.addStringPermission("user:add");
//拿到当前用户登陆对象
Subject subject= SecurityUtils.getSubject();
User currentUser= (User) subject.getPrincipal();//拿到User对象
// info.addStringPermission(currentUser.getPerms());//设置当前用户对象
return info;
}
//认证(用户的权限)
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=>认证");
// String name="陈汝旭";
// String password="123456";
//连接真实数据库
UsernamePasswordToken userToken =(UsernamePasswordToken) authenticationToken;
// if (!userToken.getUsername().equals(name)){
// return null; //抛出异常 unkonwAccountexception登录失败
// }
// //密码认证
// return new SimpleAuthenticationInfo("",password,"");
User user=userService.queryUserByName(userToken.getUsername());//获取用户名
String name=user.getName();
String password=user.getPwd();
if(user==null){//说明查无此人
return null;
}
return new SimpleAuthenticationInfo(user,password,name);
}
}
1)执行登录的方法
subject.login(token);//执行登陆的方法
2)研究一下login()的方法,进入源码
3)再进入实现类
(这个login方法大多都是赋值的操作,我们可以只抓住主要的语句分析)
4)进入这个方法Subject subject = this.securityManager.login(this, token);的实现类
5)
6)都是一些异常处理信息,主要研究info = this.doAuthenticate(token);
7)这里以单realm来研究 doSingleRealmAuthentication
()
8)再继续下钻到了这里,主要研究 realm.getAuthenticationInfo(token);可以发现getAuthenticationInfo原来是抽象接口Realm的其中一个方法
9)紧接着进入realm的其中一个实现类AuthenticatingRealm
(个人觉得研究源码可以不全看懂,尽量抓住主要的语句即可,因为获取缓存中的信息无法帮助我们研究流程,可以先不理会)
10)doGetAuthenticationInfo一直下钻进来,可以看到我们继承的子类的方法AuthenticationInfo,然后在自定义的AuthenticationInfo进行用户认证的操作。
shiro判断权限的方法有subject.isPermitted(“user”),subject.hasRole(“user”);等
以subject.isPermitted(“user”)作为研究
1)点进去它的实现类DelegatingSubject,先判断身份this.hasPrincipals(),在判断授权,所以主要研究isPermitted()
2)再继续点进去实现类AuthorizingRealm
3)主要研究getAuthorizationInfo()这个方法
4)根据上面说的经验,缓存的方法可以先不理会,这里大多也是一些异常处理信息,所以主要研究 info = this.doGetAuthorizationInfo(principals);
5)再点击进去,又到了我们的老朋友userRealm的doGetAuthorizationInfo
正常情况这里将从数据库中获取到相对应的权限信息
(为了偷懒,这里就采用写死的方式获取权限)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。