关键代码详解
首先,我们导入以来完成后,需要进行配置自定义配置shiro类,同时用@Configuration注解标注
@Configuration //自定义配置类,实现shiro的配置 public class shiroConfig{ //1. shiroFilterFactoryBean //2. DefaultWebSecurityManager 安全管理器(关联Realm) //3. 创建realm对象 }
在shiro配置类中有三个内置类是十分重要的,他们分别是
- ShiroFilterFactoryBean
- DefaultWebSecurityManager
- realm对象
他们决定了shiro的工作机制及流程
如图所示
Realm :
Realm : 作为接收需要接受的安全数据的对象,起着与我们底层的数据交互的作用,它通过封装安全数据,然后放入在Spring的容器中
//3. 创建realm对象,需要自定义类,然后交给spring托管(放到bean中) @Bean(name = "userRealm") public UserRealm userRealm(){ return new UserRealm(); }
DefaultWebSecurityManager :
DefaultWebSecurityManager : 作为安全管理员,他的作用就是来关联我们放置在容器中Realm对象,同时,将自身再封装成为Bean交给spring容器来托管,然后等待ShiroFilterFactoryBean的调用 。可以看出他是shiro的核心,相当于我们springMVC中的DispatcherServlet
//2. DefaultWebSecurityManager 安全管理器(关联Realm) //@Qualifier("userRealm")中的内容就是下面第三步中的@Bean中name属性 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //用securityManager来关联realm securityManager.setRealm(userRealm); //因为我们第三步已经将userRealm交给了spring接管,所以需要传参数来得到,而不是直接new return securityManager; }
ShiroFilterFactoryBean :
**ShiroFilterFactoryBean : 作用就是继续关联安全管理器DefaultWebSecurityManager,然后同时将自己也封装成bean **
//1. shiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //关联DefaultWebSecurityManager安全管理器 bean.setSecurityManager(defaultWebSecurityManager); /** * 添加内置过滤器 * ● anon : 无需认证即可访问 * ● authc :必须认证才能访问 * ● user :必须拥有记住我才能访问 * ● perms : 拥有对某个资源的权限才能访问 * ● role : 拥有某个角色权限才能访问 */ //拦截的请求----------------------------------- Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/vipFirst","perms[vip1]"); filterMap.put("/vipSecond","perms[vip2]"); bean.setFilterChainDefinitionMap(filterMap);//他的参数是从map集合中拿的,所以需要提前设置一个集合 //如果没有权限,设置跳转页面(登录的请求) bean.setLoginUrl("/login"); //未授权的请求 //bean.setUnauthorizedUrl(""); //------------------------------------------- return bean; }
他的拦截请求会通过一个map集合来操作,但是shiro也存在很多的内置过滤器 , 通过这些过滤器,我们就可以实现请求过滤操作
* ● anon : 无需认证即可访问
* ● authc :必须认证才能访问
* ● user :必须拥有记住我才能访问
* ● perms : 拥有对某个资源的权限才能访问
* ● role : 拥有某个角色权限才能访问
在ShiroFilterFactoryBean中我们可以做很多需要的操作比如:
- 请求的拦截
- 未授权用户页面的跳转
- ….
上述三者的执行顺序虽然是从:S - > D - > R (简写)
但是我们在按逻辑写的时候确实 从 : R- > D -> S
对外核心Subject
与应用程序的代码直接进行交互的对象就是Subject, 它代表的是当前用户,这个用户不仅仅值得是一个具体的人,而是与当前应用交互的任何事物。与Subject进行交互,他就会将所有的东西全都委托给我们的安全管理员(DefaultWebSecurityManager ),他才是真正的执行者。
对内核心Realm
为什么这里我将他作为对内核心,因为我们所有需要进行安全操作的事情都在他的实现类中完成
//3. 创建realm对象 //实现的两个方法就是 springsecurity中授权和认证 public class UserRealm extends AuthorizingRealm { //认证 // .... //授权 }
比如:
- 对用户进行授权
- 认证
- 密码保护
- …
认证
//认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("===> 执行了认证方法"); //获取当前的令牌,及其其中的信息 UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken; // 获取当前的用户 , 封装用户的登录数据(在controller的登录方法中实现) User user = userService.selectUser(userToken.getUsername()); //判断是否与数据库中的相同,如果不相同 if (!user.getUsername().equals(userToken.getUsername())){ return null; //就会抛出异常 } Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); session.setAttribute("loginUser",user); //密码认证, shrio来帮助我们实现 AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),user.getDept()); return info; }
授权
//授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("===> 执行了授权方法"); //执行授权的功能 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //将用户所具有的权限存放在数据库中,然后登录时获取用户的全部信息 Subject subject = SecurityUtils.getSubject(); //在用户进行认证时我们进行这个操作【AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),user.getDept());】 //通过他我们就可以拿到数据 User user = (User) subject.getPrincipal(); //设置当前用户的权限 authorizationInfo.addStringPermission(user.getDept()); //authorizationInfo.addRole("vip1"); return authorizationInfo; }