1.简介
Shiro 是一个强大、简单易用的 Java 安全框架,可使认证、授权、加密,会话过程更便捷,并可为应用提供安全保障。本节课重点介绍下 Shiro 的认证和授权功能。
2.Shiro的三大组件
Shiro 有三大核心组件,即 Subject、SecurityManager 和 Realm。先来看一下它们之间的关系。
2.1 Subject 为认证主体
包含 Principals 和 Credentials 两个信息。我们看下两者的具体含义。
Principals:代表身份。可以是用户名、邮件、手机号码等等,用来标识一个登录主体的身份。
Credentials:代表凭证。常见的有密码,数字证书等等。
说白了,两者代表了需要认证的内容,最常见的便是用户名、密码了。比如用户登录时,通过 Shiro 进行身份认证,其中就包括主体认证。
2.2 SecurityManager 为安全管理员
这是 Shiro 架构的核心,是 Shiro 内部所有原件的保护伞。项目中一般都会配置 SecurityManager,开发人员将大部分精力放在了 Subject 认证主体上,与 Subject 交互背后的安全操作,则由 SecurityManager 来完成。
2.3 Realm 是一个域
它是连接 Shiro 和具体应用的桥梁。当需要与安全数据交互时,比如用户账户、访问控制等,Shiro 将会在一个或多个 Realm 中查找。我们可以把 Realm 看作 DataSource,即安全数据源。一般,我们会自己定制 Realm
2.4 SpringBoot导入Shiro依赖
<!-- shiro整合Spring的包 -->
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
2.5编写ShiroConfig
使用Shiro框架,需要自己写一个Config配置 添加一下拦截、授权、跳转、关联、使用Thymeleaf一些配置
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 3
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon: 无需认证就可以访问
authc: 必须认证才能访问
user: 必须拥有 记住我 才能访问
perms: 拥有对某个资源的权限才能访问
role: 拥有某个角色权限才能访问
* */
//拦截
Map<String,String> filterMap= new LinkedHashMap<String,String>();
//需要认证才能访问以下页面
// filterMap.put("/user/add","authc");
// filterMap.put("/user/update","authc");
//授权,正常会跳转 未授权页面
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
//跳转未授权页面
bean.setUnauthorizedUrl("/noauth");
return bean;
}
//DefaultWebSecurityManager 2
@Bean(name="securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRelam")UserRelam userRelam){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//关联Relam
defaultWebSecurityManager.setRealm(userRelam);
return defaultWebSecurityManager;
}
//创建realm对象,需要自定义类 1
@Bean
public UserRelam userRelam(){
return new UserRelam();
}
//整个ShiroDiaLect 用来整合shiro thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
2.6编写用户认证类Relam
自己个人写一个用户认证类Relam,配置自己一些基础信息。
这里doGetAuthenticationInfo方法中,我使用的用户名、密码都是直接写死的,一般来说都是从数据库中取,然后再跟前端传来的token来校验
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;
//自定义Relam extends AuthorizingRealm
public class UserRelam extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
//SimpleAuthorizationInfo
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission ("user:add");
//拿到当前登录的对象
Subject subject = SecurityUtils.getSubject();
String principal = (String)subject.getPrincipal(); //可以拿到加密的时候用户对象
//设置当前用户权限,一般权限从数据库读
info.addStringPermission(principal);
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthorizationInfo");
//用户名、密码 ~数据中取
String name="root";
String password="123456";
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
//用户认证
if(!userToken.getUsername().equals(name)){
return null;//抛出异常 UnknownAccountException
}
//密码认证Shiro来做
//可以加密 MD5 MD5盐值加密
return new SimpleAuthenticationInfo(name,password,"");
}
}
2.7 Shiro一些方法
2.7.1角色验证
hasRole(String roleName)
返回true,当前Subject(登陆工号)有该角色权限,false,没有
hasRoles(List<String> roleNames)
返回true,至少在集合中存在一个角色权限,false一个都没有
hasAllRoles(Collection<String> roleNames)
返回true,当前工号拥有列表所有角色,否则返回false
2.7.2角色检查
checkRole(String roleName)
若当前Subject(工号)有该角色不抛出异常,若没有抛出AuthorizationException
checkRoles(Collection<String> roleNames)
若当前Subject(工号)拥有所有该集合角色不抛出异常,若没有抛出AuthorizationException
checkRoles(String... roleNames)
同上,只不过采用java5的新特性
2.7.3权限校验
isPermitted(Permission p)/isPermitted(String perm)
返回true,当前Subject(工号)拥有该权限,否则false
isPermitted(List<Permission> perms)/isPermitted(String... perms)
有集合中的一个以上,即返回true,否则false
isPermittedAll(Collection<Permission> perms)/isPermittedAll(String... perms)
有集合中的所有权限,才返回true,否则false
2.7.4权限检查
checkPermission(Permission p)
checkPermission(String perm)
checkPermissions(Collection<Permission> perms)
checkPermissions(String... perms)
2.8Shiro注解使用
@RequiresAuthentication
是否经过认证或者登陆,若没有的话会抛出异常UnauthenticatedException
@RequiresGuest
未认证或者叫未登陆,可能在remember me状态下,否则抛出异常UnauthenticatedException
@RequiresPermissions
检查是否有该权限,没有抛出异常AuthorizationException
@RequiresRoles
检查是否有该角色,没有抛出异常AuthorizationException
@RequiresUser
这个刚好跟@RequiresGuest相反,这个必须经过认证,或者从rememberme进行登陆,
这个没有RequiresAuthentication严格但类似,否则抛出异常AuthorizationException
以上是我学习Shiro中一些基础的心得,希望能帮助到一些刚学的朋友,具体更详细的东西,可以参考其他博客