简介
Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。
本教程只介绍基本的 Shiro 使用,不会过多分析源码等,重在使用。
Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。这不就是我们想要的嘛,而且 Shiro 的 API 也是非常简单;
Authentication:验证用户身份,一般多用于登录验证
Authorization:授权验证,通过身份验证后,在进行权限验证,验证不同身份的权限做对应的操作
Session Management: 会话管理,登录成后,只要没有退出登录,回话一直保持,
Concurrency: 加密解密
Web Support: 支持web环境
Testing: 支持测试
Remember Me: 缓存
工作流程:
代码生成后>先经过subject门槛>securityManager进行安全验证>realm拿数据
进行登录验证时,shiro会将用户输入的密码和用用户名查到的密码进行对比是否相同
shiro的简单使用:
1.加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
2.修改配置
2.1声明一个自定义的realm
名字=路径
customRealm=com.woniuxy.framework.component.MyRealm
2.2将realm植入到securityManager中
securityManager.realms=$customRealm
3编写Realm
package com.woniuxy.framework.component;
import com.alibaba.druid.pool.DruidDataSource;
import com.woniuxy.framework.model.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.security.auth.login.AccountNotFoundException;
import java.util.List;
public class MyRealm extends AuthorizingRealm {
private static JdbcTemplate jdbcTemplate = null;
static{
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/edu");
dataSource.setUsername("root");
dataSource.setPassword("123321");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
jdbcTemplate = new JdbcTemplate(dataSource);
}
/**
* 获取授权信息
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 获取认证信息
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("进入获取认证信息方法:"+token);
//获取到用户名
Object username = token.getPrincipal();
//查询用户
List<User> userList = jdbcTemplate.query(
"select * from edu_user where username=?", //sql
new BeanPropertyRowMapper<User>(User.class), //结果映射器,将ResultSet中的内容自动映射到User类上
username);//参数
//判断结果
if(userList.size()==0){
throw new UnknownAccountException(username+"用户不存在");
}
if(userList.size()>1){
throw new AccountException("系统异常,找到多个用户"+username);
}
//适配返回对象, 用户、密码、Realm名字
return new SimpleAuthenticationInfo(userList.get(0),userList.get(0).getPassword(),MyRealm.class.getName());
}
}
4测试
//加载配置文件,创建工厂类
IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shirodb.ini");
//创建安全管理器
SecurityManager securityManager = iniSecurityManagerFactory.getInstance();
//将安全管理器设置到SecurityUtils中
SecurityUtils.setSecurityManager(securityManager);
//获取Subject对象,代表一个用户
Subject subject = SecurityUtils.getSubject();
//认证
subject.login(new UsernamePasswordToken("zhangsan","wohenshuai"));
System.out.println("zhangsan"+subject.isAuthenticated());
subject.login(new UsernamePasswordToken("laoliu","wohenshuai"));
System.out.println("laoliu"+subject.isAuthenticated());
shiro集成到Spring的使用
原理图
注意:过滤器的验证和shiro的验证并不会冲突,接收到请求后,经过过滤器首次验证后,在经过shiro验证,通过后,在回到过滤器验证.
实现步骤
1.导依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.1</version>
</dependency>
2.改配置(在配置类中加允许通过的请求头)
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition sfcd = new DefaultShiroFilterChainDefinition();
sfcd.addPathDefinition("/", "anon");
sfcd.addPathDefinition("/login", "anon");
sfcd.addPathDefinition("/login.html", "anon");
sfcd.addPathDefinition("/css/**", "anon");
sfcd.addPathDefinition("/js/**", "anon");
sfcd.addPathDefinition("/images/**", "anon");
sfcd.addPathDefinition("/fonts/**", "anon");
sfcd.addPathDefinition("/html/**", "anon");
sfcd.addPathDefinition("/logout", "logout");
sfcd.addPathDefinition("/**", "user");
return sfcd;
}
shiro.loginUrl=/login.html
Filter Name | 功能 |
anno | 不需要授权、登录就可以访问。eg:/index |
authc | 需要登录授权才能访问。eg:/用户中心 |
authcBasic | Basic HTTP身份验证拦截器 |
logout | 退出拦截器。退出成功后,会 redirect到设置的/URI |
noSessionCreation | 不创建会话连接器 |
perms | 授权拦截器:perm['user:create'] |
port | 端口拦截器.eg:port[80] |
rest | rest风格拦截器 |
roles | 角色拦截器。eg:role[administrator] |
ssl | ssl拦截器。通过https协议才能通过 |
user | 用户拦截器。eg:登录后(authc),第二次没登陆但是有记住我(remmbner)都可以访问。 |
在需要验证权限的接口上方标注[@RequiresPermissions("权限")]
@GetMapping("/buy")
@RequiresPermissions("上课")
public String buy(){
return "success";
}