目录
一、依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
二、配置类
---ShiroConfig.java
@Configuration
public class ShiroConfig{
/**
* ShiroFilterFactoryBean
* 获取shiro过滤器
* 主要配置需要拦截的路径
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Autowired DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//关联DefaultWeSecurityManager 安全管理器对象
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
/*
添加shiro的内置过滤器
用于添加需要拦截的路径,并设置拦截级别
拦截级别:,
anon :无需认证就可以访问
authc:必须认证了才能访问,
user: 必须拥有 remeberMe(记住我)功能才能访问
perms:拥有对某个资源的权限才能访问
roles: 拥有某个角色才能访问
*/
Map<String,String> interceptMap=new HashMap<>();
//例如 拦截 修改个人资料 功能,设置为需要登录认证才能访问
//interceptMap.put("/user/add","authc");
//此处设置放行路径
interceptMap.put("/user/*","anon");
//使用通配符拦截所有请求
interceptMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(interceptMap);
return shiroFilterFactoryBean;
}
//DefaultWeSecurityManager
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Autowired ShiroRealm shiroRealm){
DefaultWebSecurityManager webSecurityManager=new DefaultWebSecurityManager();
//关联自定义realm对象
webSecurityManager.setRealm(shiroRealm);
return webSecurityManager;
}
//创建 realm 对象,需要自定义类继承 AuthorizingRealm抽象类,并实现其抽象方法
@Bean
public ShiroRealm getDhiroRealm(){
return new ShiroRealm();
}
}
三、自定义 realm 类
具体实现等后面再说
public class ShiroRealm extends AuthorizingRealm {
/**
* 访问授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
四、控制器中的操作
@GetMapping("/tologin")
public String toLogin(){
//通过 SecurityUtils 工具类 获取当前的用户(Subject)
Subject subject= SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
/*
认证用户身份,此操作将转移到 自定义 realm对象类中的认证方法中
认证失败则会抛出如下异常
*/
try{
subject.login(token);
}catch (UnknownAccountException e){
System.out.println("用户不存在");
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
}catch (LockedAccountException e){
System.out.println("账户被锁定");
}
return "";
}
五、定义登录认证规则
现在我们回到 ShiroRealm 类中 制定认证规则
我们需要在 doGetAuthenticationInfo()方法中制定用户名校验规则
最终执行用户名比较的是 SimpleAccountRealm 类
而最终执行密码比较的是 SimpleAuthenticationInfo 类
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//数据库操作,获取用户信息,此处不演示
String name="zs";
String password="123456";
//从token中获取登录方法传递过来的用户名
String principal = (String) authenticationToken.getPrincipal();
//判断用户是否存在
if(!principal.equals(name)){
//返回空则默认抛出(UnknownAccountException)用户不存在的异常
return null;
}
//认证密码
// 参数1:数据库中用户名 参数2:数据库中密码 参数3:realmName,系统运行时会自动生成,通过父类的方法获取realmName
return new SimpleAuthenticationInfo(name,password,this.getName());
}
六、授权
授权,即访问控制,控制谁能访问那些资源,主体(Subject)进行身份认证后需要分配权限(Permission)方可访问系统资源(Rsource),对于某些资源没有权限是无法访问的。
授权方式:
- 基于角色的访问控制 例:subject.hasRole("admin")
- 基于资源的访问控制 例:subject.isPermission("user:*:create")
权限字符串的命名规则
资源标识符:操作:资源实例标识符
例如:
- 用户创建权限:user:create ,或 user:create:*
- 用户修改实例001的权限 user:update:001
- 用户操作实例001的所有权限 user:*:001
我们现在回到控制器中,在对用户进行认证之后,我们就可以对用户进行授权
1、使用编程式进行授权
@GetMapping("/tologin")
public String toLogin(){
//通过 SecurityUtils 工具类 获取当前的用户(Subject)
Subject subject= SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
/*
认证用户身份,此操作将转移到 自定义 realm对象类中的认证方法中
认证失败则会抛出如下异常
*/
try{
subject.login(token);
}catch (UnknownAccountException e){
System.out.println("用户不存在");
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
}catch (LockedAccountException e){
System.out.println("账户被锁定");
}
//1、使用 基于角色的访问控制 的授权方式
// 认证通过之后对用户进行授权
//单角色
if(subject.hasRole("admin")){ // 此处将进入自定义 realm对象中的doGetAuthorizationInfo方法中进行验证
}
//多角色
if(subject.hasAllRoles(Arrays.asList("admin","user"))){ // 此处将进入自定义 realm对象中的doGetAuthorizationInfo方法中进行验证
}
//是否具有其中一个角色
subject.hasRoles(Array.asList("admin","user")){
}
//使用 基于资源的访问控制 的授权方式
boolean hasPermission=subject.isPermitted("user:*:*");
return "";
}
在realm对象中定制授权操作
/**
* 授权(只有当需要检测用户权限的时候才会调用此方法)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取权限对象
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
//获取用户的主身份信息,
String userName=(String)principals.getPrimaryPrincipal();
//基于角色的访问控制
//此处查询数据库,获取当前用户的角色
List<String> Roles=new ArrayList<>();
//将数据库中查询出来的所有角色赋值给 simpleAuthorizationInfo 权限对象
simpleAuthorizationInfo.addRoles(Roles);
//基于权限的访问控制
//此处查询数据库,获取当前用户的角色权限
List<String> permissions=new ArrayList<>();
//将数据库中查询出来的所有角色权限赋值给 simpleAuthorizationInfo 权限对象
simpleAuthorizationInfo.addStringPermissions(permissions);
return simpleAuthorizationInfo;
}
2、使用注解式进行授权
注解需要加在控制器中的方法中,表示在进入该方法前判断用户是否有权限
@RequestMapping("/order")
@Controller
public class OrderController(){
@RequiresRoles("admin")//判断角色是否有该角色
@RequiresRoles({"admin","user"})//判断角色是否有多个角色
@RequiresPermissions("order:save")//判断角色是否有该权限
@GetMapping("/save")
public String save(){
//操作
}
}
七、总结:
springboot中使用shiro的使用步骤简化如下:
- 添加依赖
- 配置类,需要配置三个bean
- ShiroFilterFactoryBean 关联 DefaultWebSecurityManager 配置拦截路径
- DefaultWebSecurityManager 关联 ShiroRealm
- ShiroRealm 获取自定义ShiroRealm类
- 自定义 ShiroRealm 类
- 实现 doGetAuthorizationInfo() 此方法实现授权操作规则
- 实现 doGetAuthenticationInfo() 此方法实现认证操作规则
- 控制器中操作 :
- 在登录方法中使用subject.login(token)方法进行用户认证
- 制定ShiroRealm类中的doGetAuthorizationInfo()方法
- 授权
- 基于角色的访问控制
- 使用subject.hasRole()方法判断是否有操作权限
- 在控制器中的方法中添加@RequiresRoles("")注解
- 基于权限的访问控制
- 使用subject.isPermitted()方法判断是否有操作权限
- 在控制器中的方法中添加@RequiresPermissions("")注解
- 基于角色的访问控制
下一章节将讲解如何实现密码加密加盐,以及整合Redis进行缓存