Shiro
1、Shiro的简介
1.1Shiro特性
Shiro把Shiro开发团队称为“应用程序的四大基石”——身份验证,授权,会话管理和加密作为其目标。
- Authentication:有时也简称为“登录”,这是一个证明用户是他们所说的他们是谁的行为。
- Authorization:访问控制的过程,也就是绝对“谁”去访问“什么”。
- Session Management:管理用户特定的会话,即使在非 Web 或 EJB 应用程序。
- Cryptography:通过使用加密算法保持数据安全同时易于使用。
1.2 Shiro架构
Subject
:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject,一个Subject可以是一个人,但它还可以代表第三方服务,daemon account,cron job,或其他类似的任何东西——基本上是当前正与软件进行交互的任何东西。
SecurityManager
SecurityManager是Shiro架构的心脏,并作为一种“保护伞”对象来协调内部的安全组件共同构成一个对象图。然而,一旦SecurityManager和它的内置对象图已经配置给一个应用程序,那么它单独留下来,且应用程序开发人员几乎使用他们所有的时间来处理Subject API。当你正与一个Subject进行交互时,实质上是幕后的 SecurityManager处理所有繁重的Subject安全操作。
quickStart:
Subject
//获取当前用户对象的Subject
Subject currentUser = SecurityUtils.getSubject();
//通过当前用户拿到session
Session session = currentUser.getSession();
//判断当前的用户是否被认证
if (!currentUser.isAuthenticated())
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
//是否获取角色
currentUser.hasRole("schwartz")
2、Springboot中集成
2.1 导入依赖
Shiro整合Spring依赖
:
<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>
2.2 两个Config
ShiroConfig | UserRealm |
---|---|
2.3 Shiro登录拦截
注意@Bean和 @Configuration
不能丢
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean:3
@Bean
public ShiroFilterFactoryBean getShiroFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证了才能访问
user: 必须要拥有 记住我 功能才能用
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
LinkedHashMap<String, String> filterMap =new LinkedHashMap<>();
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
return bean;
}
//DefaultWebSecurityMangger:2
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象,需要自定义类:1
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
2.4 Shiro整合Mybatis
-
导入依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
-
application.yml
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
type-aliases-package: com.example.demo.pojo
mapper-locations: classpath:mapper/*.xml
- 用户名和密码存入数据库中
UserRealm
中:
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
//用户名,密码 数据库中取
// String name="root";
// String password="123456";
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
User user = userService.queryUserByName(userToken.getUsername());
if(user==null){
return null;
}
// if(!userToken.getUsername().equals(name)){
// return null;//抛出异常
// }
//密码认证
return new SimpleAuthenticationInfo("",user.getPwd(),"");
}
- Controller中
public String login(String username,String password,Model model){
//获取当前用户
Subject subject= SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);//执行登录方法,如果没有异常就说明通过
return "index";
} catch (UnknownAccountException e) {//用户名不存在
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e) {//密码不存在
model.addAttribute("msg","密码不存在");
return "login";
}
}
-
权限操作(vip)
ShiroConfig中
://授权,正常情况下,没有授权会跳转到未授权的页面 filterMap.put("/user/add","perms[user:add]");
Controller中添加未授权的页面
@RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未经授权无法访问此页面"; }
ShiroConfig中
://未授权的页面 bean.setUnauthorizedUrl("/noauth");
UserRealm
中://授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了授权"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("user:add"); return info; }
对用户有区分,需在数据库中设置一个perm,设置权限等级
-
设置后
UserRealm
认证中:return new SimpleAuthenticationInfo(user,user.getPwd(),"");
UserRealm
授权中://拿到当前登录的对象 Subject subject = SecurityUtils.getSubject(); User currentUser =(User) subject.getPrincipal(); info.addStringPermission(currentUser.getPerms()); return info;
2.5 Shiro整合Thymeleaf
-
导入依赖
<dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
-
ShiroConfig
中:
@Bean
//整合ShiroDialect :用来整合 Shiro和Thymeleaf
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
- 前端
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>