两个基本的概念
安全实体:系统需要保护的具体对象数据
权限:系统相关的功能操作,例如基本的CRUD
Shiro
首先Shiro较之 Spring Security,Shiro在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势。
Shiro是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:
Shiro四大核心功能:Authentication,Authorization,Cryptography,Session Management
Shiro架构
Shiro三个核心组件:Subject, SecurityManager 和 Realms.
Subject:主体,可以看到主体可以是任何可以与应用交互的 “用户”;
SecurityManager:相当于 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的 FilterDispatcher;是 Shiro 的心脏;所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源
两个配置类ShiroConfig和UserRealm
package com.example.shirodemo.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;
/**
* shiro配置类
*/
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*/
@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<>();
/* filterMap.put("/add","authc");
filterMap.put("/update","authc");*/
// filterMap.put("/test","anon");
filterMap.put("/login","anon");
//添加Shiro授权拦截器
filterMap.put("/add","perms[添加]");
filterMap.put("/foresee","perms[预言未来]");
filterMap.put("/update","perms[修改]");
filterMap.put("/delete","perms[删除]");
//filterMap.put("/update","perms[]");
//filterMap.put("/delete","perms[]");
//filterMap.put("/getAll","perms[]");
filterMap.put("/*","authc");
//跳转到登陆的页面
shiroFilterFactoryBean.setLoginUrl("/tologin");
//设置未授权的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*/
@Bean("securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
*/
@Bean("userRealm")
public UserRealm getRealm(){
UserRealm userRealm=new UserRealm();
return userRealm;
}
/**
* 配置shiroDialect,用于thymeleaf和shiro标签配合使用
*/
@Bean
public ShiroDialect getShiroDialect(){
ShiroDialect shiroDialect=new ShiroDialect();
return shiroDialect;
}
}
package com.example.shirodemo.config;
import com.example.shirodemo.bean.Permission;
import com.example.shirodemo.bean.User;
import com.example.shirodemo.service.IPermissionService;
import com.example.shirodemo.service.IUserService;
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.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义Realm
*/
public class UserRealm extends AuthorizingRealm {
@Resource
private IUserService userService;
@Resource
private IPermissionService permissionService;
/**
* 执行授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
/**
* 给资源授权
*/
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
//添加授权字符串
//simpleAuthorizationInfo.addStringPermission("user:add");
//--------------------认证账号
Subject subject= SecurityUtils.getSubject();
User user=(User)subject.getPrincipal();
User user1=userService.findById(user.getId());
if(user1==null){
//用户名不存在
return null;
}
//-------------------开始授权
List<Permission> permissions =permissionService.getPermissionByUserId(user1.getId());
for (Permission per : permissions) {
simpleAuthorizationInfo.addStringPermission(per.getName());
System.out.println("拥有权限:"+per.getName());
}
return simpleAuthorizationInfo;
}
/**
* 执行认证逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
/**
* 判断ShiroRealm逻辑UsernamePasswordToken是否正确
*/
//1判断用户名
UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken)authenticationToken;
User user=userService.findByname(usernamePasswordToken.getUsername());
if(user==null){
//用户名不存在
return null;
}
//判断密码是否正确
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
认证过程
/**
* 登录逻辑处理
*/
@RequestMapping("/login")
public String login(User user, Model model) {
/**
*使用shiro编写认证操作
*/
//1:获取subject
Subject subject = SecurityUtils.getSubject();
//2:封装用户账号和密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword());
//3:执行登录方法
try {
subject.login(usernamePasswordToken);
model.addAttribute(user);
//登录成功
//成功后跳转到
//return "redirect:/test";
return "/test";
} catch (UnknownAccountException e) {
//e.printStackTrace();
//登录失败用户名不存在
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
//登录失败密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
}
Spring Security和Shiro
相同点:
1:认证功能
2:授权功能
3:加密功能
4:会话管理
5:缓存支持
6:rememberMe功能.......
不同点:
优点:
1:Spring Security基于Spring开发,项目中如果使用Spring作为基础,配合Spring Security做权限更加方便,而Shiro需要和Spring进行整合开发
2:Spring Security功能比Shiro更加丰富些,例如安全防护
3:Spring Security社区资源比Shiro丰富
缺点:
1:Shiro的配置和使用比较简单,Spring Security上手复杂
2:Shiro依赖性低,不需要任何框架和容器,可以独立运行,而Spring Security依赖于Spring容器