Shiro执行逻辑
- Application Code:编写的应用程序
- Subject: 主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者;
- SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;
- Realm:领域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。
最简单的一个Shiro应用
- 应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager;
- 我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。
Shiro的组织架构
由图看出,Security Manager是最复杂的系统
Security Manager内部
- Authenticator:认证器,负责主体认证的,这是一个扩展点,如果用户觉得 Shiro 默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
- Authorizer:授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;
- SessionManager:如果写过 Servlet 就应该知道 Session 的概念,Session 呢需要有人去管理它的生命周期,这个组件就是 SessionManager;而 Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境、EJB 等环境;所以呢,Shiro 就抽象了一个自己的 Session 来管理主体与应用之间交互的数据;这样的话,比如我们在 Web 环境用,刚开始是一台 Web 服务器;接着又上了台 EJB 服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到 Memcached 服务器);
- SessionDAO:DAO 大家都用过,数据访问对象,用于会话的 CRUD,比如我们想把 Session 保存到数据库,那么可以实现自己的 SessionDAO,通过如 JDBC 写到数据库;比如想把 Session 放到 Memcached 中,可以实现自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 进行缓存,以提高性能;
- CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能
- Cryptography:密码模块,Shiro 提供了一些常见的加密组件用于如密码加密 / 解密的。
领域Realm的实现
可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是 JDBC 实现,也可以是 LDAP 实现,或者内存实现等等;由用户提供;注意:Shiro 不知道你的用户 / 权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的 Realm;
Shiro身份验证
身份验证,即在应用中谁能证明他就是他本人。一般提供如他们的身份 ID 一些标识信息来表明他就是他本人,如提供身份证,用户名 / 密码来证明。
shiro中进行身份验证,需要提供principals
(身份)和credentials
(证明)
身份告诉shiro你是什么用户,证明用来证明你是这个身份。
最常见的principals
和credentials
就是用户名和密码了
principals = 用户名/邮箱/手机号等等
credentials = 密码/验证码/数字凭证等等
下面利用springboot环境来演示Shiro如何进行身份验证
演示
准备环境依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
准备用户身份
采用shiro.ini
配置文件指定两个subject,一个用户名为wang,密码123,一个为zhang,密码123
[users]
wang = 123
zhang = 123
测试代码
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
public void MainTest(){
// 初始化SecurityManager工厂,这里用ini文件作为realm
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
// 利用工厂产生一个SecurityManager实例
SecurityManager securityManager = factory.getInstance();
// 将sm实例绑定到shiro提供的工具类中,下面的操作要利用此工具类
SecurityUtils.setSecurityManager(securityManager);
// 获得主体,这里的主体是ini文件中的两个用户
Subject subject = SecurityUtils.getSubject();
// 利用shiro提供的类创建一个虚拟用户用来登录
UsernamePasswordToken token = new UsernamePasswordToken("wang", "123");
try {
// 对身份进行验证
subject.login(token);
} catch (AuthenticationException e) {
System.out.println("用户名和密码错误,错误信息:"+e.getMessage());
}
// 判断用户是否验证通过,通过返回true,不通过返回false
boolean authenticated = subject.isAuthenticated();
if(authenticated) System.out.println("登录成功");
else System.out.println("登录失败");
// 退出登录
subject.logout();
}
}
对29行错误信息的解释
如果身份验证失败请捕获 AuthenticationException
或其子类,常见的如: DisabledAccountException
(禁用的帐号)、LockedAccountException
(锁定的帐号)、UnknownAccountException
(错误的帐号)、ExcessiveAttemptsException
(登录失败次数过多)、IncorrectCredentialsException
(错误的凭证)、ExpiredCredentialsException
(过期的凭证)等,具体请查看其继承关系;对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库;
从如上代码可总结出身份验证的步骤:
- 收集用户身份 / 凭证,即如用户名 / 密码;
- 调用
Subject.login
进行登录,如果失败将得到相应的AuthenticationException
异常,根据异常提示用户错误信息;否则登录成功; - 最后调用
Subject.logout
进行退出操作。
如上测试的几个问题:
- 用户名 / 密码硬编码在
ini
配置文件,以后需要改成如数据库存储,且密码需要加密存储; - 用户身份
Token
可能不仅仅是用户名 / 密码,也可能还有其他的,如登录时允许用户名 / 邮箱 / 手机号同时登录。
从代码可以看出这些操作好像是subject完成的,但实际上,全部是subject委托给securityManager完成的,而SecurityManager对于身份验证的操作,会交给自己的子模块Authenticator完成,Authenticator将获取到的token(用户信息及凭证)交给realm,realm如果没有抛出异常,那么身份就验证成功了。
可以看出,Realm是验证身份的最终站,因此,我们可以配置多个Realm来多次验证Authenticator交过来的token
Realm配置
Realm是安全数据源,我们刚刚的演示中使用了ini文件作为数据源,那么我们使用的Realm在shiro中就是
org.apache.shiro.realm.text.IniRealm
shiro中定义了Realm接口,他是所有Realm的父类接口,代码如下
String getName(); //返回一个唯一的Realm名字
boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException; //根据Token获取认证信息
我们可以自定义Realm,然后通过ini配置文件指定securityManager的Realm实现,这样便可实现多Realm验证
创建一个shiro-multi-realm.ini
文件,假设现在我们自定义了两个Realm
那么可以通过下面的配置文件进行多Realm配置
\#声明一个realm
myRealm1 = com.whr.realm.MyRealm1
myRealm2 = com.whr.realm.MyRealm2
\#$符号表示引用上面已经定义好的对象
\#指定securityManager的realms实现,这一行可删除,删除后将按照上面声明的顺序加载
securityManager.realms=$myRealm1,$myRealm2
securityManager
会按照 realms
指定的顺序进行身份认证。此处我们使用显示指定顺序的方式指定了 Realm
的顺序,如果删除 “securityManager.realms=$myRealm1,$myRealm2”,那么securityManager
会按照 realm
声明的顺序进行使用(即无需设置 realms
属性,其会自动发现),当我们显示指定 realm
后,其他没有指定 realm
将被忽略,如 “securityManager.realms=$myRealm1”,那么 myRealm2
不会被自动设置进去。
Shiro提供的Realm
以后一般继承 AuthorizingRealm
(授权)即可;其继承了 AuthenticatingRealm
(即身份验证),而且也间接继承了 CachingRealm
(带有缓存实现)。
Shiro授权
为什么需要授权,因为在页面中,有些资源我们不想让没有权限的人看到,例如在一个后台管理系统登录窗口页面,我们会有几个角色,例如:管理员(admin),用户(user)等等,那么管理员和用户能看到的页面和进行的操作一定是不同的。这时我们就需要对不同的角色进行授权。
在授权中需了解的几个关键对象:
-
主体(Subject)即访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权后才允许访问相应的资源。
-
资源(Resource) 在应用中用户可以访问的URL,比如访问 JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
-
权限(Permission) 安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如: 访问用户列表页面 查看/新增/修改/删除用户数据(即很多时候都是 CRUD(增查改删)式权限控制)打印文档等。如上可以看出,权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允许,不反映谁去执行这个操作。所以后续还需要把权限赋予给用户,即定义哪个用户允许在某个资源上做什么操作(权限),Shiro 不会去做这件事情,而是由实现人员提供。
-
角色(Role)。 角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。
授权方式
Shiro 支持三种方式的授权:
编程式:通过写 if/else 授权代码块完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
注解式:通过在执行的 Java 方法上放置相应的注解完成:
@RequiresRoles("admin")
public void hello() {
//有权限
}
没有权限将抛出相应的异常;
JSP/GSP 标签:在 JSP/GSP 页面通过相应的标签完成:
<shiro:hasRole name="admin">
<!— 有权限 —>
</shiro:hasRole>
演示
基于角色的演示控制
[users]
wang = 123 ,admin,user
zhang = 123 ,user
给wang用户设置了两个角色,admin和user,zhang用户只有user角色
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
/*
* 利用静态代码块完成securityManager的注册,但是大多数情况下是不用这样做的,这里仅作测试
* */
static {
SecurityManager securityManager = new IniSecurityManagerFactory("classpath:shiro.ini").
getInstance();
SecurityUtils.setSecurityManager(securityManager);
}
@Test
public void MainTest(){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken zhang = new UsernamePasswordToken("zhang", "123");
subject.login(zhang);
if(subject.hasRole("admin")){
System.out.println("have permission");
}else{
System.out.println("don't have permission");
}
// 退出登录
subject.logout();
}
}
上述示例只演示了测试此用户是否拥有某一角色,下面给此角色赋予权限
[users]
zhang=123,admin,user
wang=123,user
[roles]
admin = admin:create,admin:delete,admin:update
user = user:read
@Test
public void MainTest(){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken zhang = new UsernamePasswordToken("zhang", "123");
subject.login(zhang);
if(subject.hasRole("user")){
System.out.println("have role");
// 判断此用户是否拥有删除权限,没有则报错
try{
subject.checkPermission("admin:delete");
}catch(UnauthorizedException e){
System.out.println(e.getMessage());
}
}else{
System.out.println("don't have role");
}
// 退出登录
subject.logout();
}
//报错信息
Subject does not have permission [admin:delete]
Springboot集成Shiro
开始之前,所有页面结构
在pom.xml中添加如下三个依赖
<!--shiro核心包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<!--shiro与spring整合的jar包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<!--thymeleaf依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
在yml文件中进行配置
spring:
thymeleaf:
#配置模板路径,默认是templates,可以不用配置
prefix: classpath:/templates/
suffix: .html
cache: false #关闭页面缓存
自定义一个MyShiroConfig
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;
/**
* @author
* @description
*/
@Configuration
public class MyShiroConfig {
// 利用securityManager对象来注册shiroFilter
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean
(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
// 关联SecurityManager
shiroFilter.setSecurityManager(defaultWebSecurityManager);
return shiroFilter;
}
// 注册SecurityManager对象,其中底层的realm用自己的实现
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
// 注册realm,这个realm是自定义的
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
自定义一个Realm
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* @author
* @description
*/
public class UserRealm extends AuthorizingRealm {
// 给用户授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行doGetAuthorizationInfo-PrincipalCollection");
return null;
}
// 认证用户的token
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行doGetAuthorizationInfo-AuthenticationToken");
return null;
}
}
上面的代码自定义了UserRealm,这个说明了SecurityManager需要realm时的访问对象,然后定义了一个过滤器,这个过滤器可以拦截用户的请求并进行页面的跳转
在前端控制器中拿到前端发来的数据后,封装成token,交付给SecurityManager对象,sm再去Realm中去验证用户的身份及权限。
例如,我们拥有下面的一个Controller控制器
@RequestMapping("/userLogin")
public String login(String username, String password, Model model){
// 获取当前登录的用户
Subject subject = SecurityUtils.getSubject();
// 封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try{
// 这里的login将会把token交付给securityManager,sm再去UserRealm中认证用户
subject.login(token);
// 登录成功跳转
return "index";
}catch (UnknownAccountException e){
//用户名不存在
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
//密码不正确
model.addAttribute("msg","密码错误");
return "login";
}
}
当用户发起/userLogin
请求时,前端将用户名和密码封装成一个token,同时调用subject的login方法,会将token交给SM对象,SM对象再访问UserRealm
中去验证用户身份
拦截用户请求
如果想要拦截用户请求,那么需要在MyShiroConfig
类中修改shiroFilter
进行配置
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean
(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(defaultWebSecurityManager);
// 添加shiro的内置过滤器,对请求进行拦截
/*
anno:无需认证即可访问 默认的
authc:必须认证才可以访问
user:必须记住我才能访问
perms:拥有对某个资源的权限才能访问
role: 拥有某个角色的权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
/*
配置后,shiro将会对用户发来的这两个请求进行拦截并认证
filterMap.put("/user/add","authc");
filterMap.put("/user/delete","authc");
*/
filterMap.put("/user/*","authc");
shiroFilter.setFilterChainDefinitionMap(filterMap);
// 如果没有权限就跳转到login页面
shiroFilter.setLoginUrl("/login");
return shiroFilter;
}
此时用户想要访问这两个请求时,会跳转到login页面,而login页面将会发起/userLogin
请求
认证用户
在UserRealm中的第二个重载方法中这样写
// 认证用户的交付过来的token
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行doGetAuthorizationInfo-AuthenticationToken");
// 假定的用户名和密码。实际开发中去数据库中取
String username = "root";
String password = "123456";
// 由于传入的是UsernamePasswordToken,这里需要向下转型
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
if (!token.getUsername().equals(username)) {
// 如果用户名和假定用户名不匹配,返回null,抛出一个UnKnownAccountException异常
return null;
}
// 用户名的判断我们自己做,而密码的判断需要交给shiro做,并且判断时shiro会自动调取token中的password
return new SimpleAuthenticationInfo("",password,"");
}
密码加密
密码加密前需要将数据库或假定的密码测试出来结果
shiro共有两种加密方式
-
SimpleCredentialsMatcher(简单证明匹配): SimpleCredentialsMatcher对存储的用户凭证和从AuthenticationToken提交的用户凭证直接执行相等的检查。
-
HashedCredentialsMatcher:取代将凭证按它们原始形式存储并执行原始数据的对比,存储终端用户的凭证(如密码)更安全的办法是在存储数据之前,先进行hash运算。
shiro的加密算法
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
public void MainTest(){
Md5Hash md5Hash = new Md5Hash("123456");
System.out.println("md5Hash.getAlgorithmName()="+md5Hash.getAlgorithmName());//默认为MD5
System.out.println("md5Hash.getSalt()="+md5Hash.getSalt()); //默认为null
System.out.println("md5Hash.getIterations()="+md5Hash.getIterations());//默认为1
// 不加盐,散列次数为1的加密结果
System.out.println(md5Hash);
// 加盐,盐值一般为用户名,散列次数为1的加密结果
md5Hash = new Md5Hash("123456","root");
System.out.println(md5Hash);
// 一般开发种,加盐,并且加密次数为3次
md5Hash = new Md5Hash("123456","root",3);
System.out.println(md5Hash);
//4.利用SimpleHash来设置md5(上面三种都可以通过这个来设置,这里举例加盐加散列次数的)
//第一个参数是算法名称,这里指定md5,第二个是要加密的密码,第三个参数是加盐,第四个是散列次数
SimpleHash hash = new SimpleHash("md5", "123456", "root",3);
System.out.println(hash.toString());
}
}
授权
在MyShiroConfig
中配置过滤器要授权的请求地址
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean
(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(defaultWebSecurityManager);
// 添加shiro的内置过滤器,对请求进行拦截
/*
anno:无需认证即可访问 默认的
authc:必须认证才可以访问
user:必须记住我才能访问
perms:拥有对某个资源的权限才能访问
role: 拥有某个角色的权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
/*
配置后,shiro将会对用户发来的这两个请求进行拦截并认证
filterMap.put("/user/add","authc");
filterMap.put("/user/delete","authc");
*/
// 配置权限,配置权限一定要在认证前才能生效
filterMap.put("/user/add","perms[user:add]");
// 给delete请求设置只有拥有权限才能访问,此时会跳转到realm中
filterMap.put("/user/delete","perms[user:delete]");
filterMap.put("/user/*","authc");
shiroFilter.setFilterChainDefinitionMap(filterMap);
// 如果没有权限就跳转到login页面
shiroFilter.setLoginUrl("/login");
// 如果没有授权就跳转到未授权页面
shiroFilter.setUnauthorizedUrl("/unauth");
return shiroFilter;
}
修改UserRealm
如下
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;
/**
* @author
* @description
*/
public class UserRealm extends AuthorizingRealm {
// 给用户授权,每次过滤器拦截到perms[user:add]都会跳转到此进行授权认证
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行doGetAuthorizationInfo-PrincipalCollection");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
// 如果此用户有角色,只需要addRole即可
// simpleAuthorizationInfo.addRole("role");
Subject subject = SecurityUtils.getSubject();
// 通过下面这两个方法都可以拿到认证用户方法传来的perms
String perms = (String) subject.getPrincipal();
// String perms = principalCollection.getPrimaryPrincipal();
// 将此权限赋予给此用户
simpleAuthorizationInfo.addStringPermission(perms);
return simpleAuthorizationInfo;
}
// 认证用户的交付过来的token
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行doGetAuthorizationInfo-AuthenticationToken");
// 假定的用户名和密码。实际开发中去数据库中取
String username = "root";
String password = "123456";
// 假定用户只有add权限没有delete权限
String perms = "user:add";
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
if (!token.getUsername().equals(username)) {
return null;
}
// 将用户的权限perms通过此返回值传输到doGetAuthorizationInfo方法中,实际开发中传输对象
return new SimpleAuthenticationInfo(perms,password,"");
}
}
到此springboot的基本操作就演示完毕了,在jsp的页面中,shiro可以利用标签进行一些测试,在thymeleaf中也可以利用标签,只不过需要加载新的jar包,是thymeleaf和shiro整合的jar包,具体的我没有研究,具体用到再说。