(1)Subject:代表了当前"用户",这个用户不一定是一个具体的人, 与当前应用交互的任何东西都是Subject。
(2)SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且其管理着所有Subject;可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherServlet的角色。
(3)Authenticator:认证。验证用户是否合法,也就是登录。利用Shiro进行密码匹配,帮我们完成登录。
(4)Authorizer:授权。授予谁具有访问哪些资源的权限;即判断用户是否能做事情,常见的如:当我们点一个链接或按钮时,Shiro会帮我们判断有没有这个权限。验证某个用户是否拥有某个角色,或者细粒度的验证某个用 户对某个资源是否具有某个权限。
(5)Session Manager:会话管理。用户登录后的用户信息通过Session Manager来进行管理,不管是什么应用中,比如:Web应用、JavaSE应用。之前我们在Web环境下,使用的是HttpSession。那使用Shiro的情况下即便是在非Web环境下,就是说在JavaSE环境系也可以使用session,这个session就是Shiro帮我们提供的。
(6)SessionDAO 即会话 dao,是对 session 会话操作的一套接口,比如要将 session 存储到数据库,可以通过 jdbc 将会话存储到数据库。
(7)Cache Manager缓存管理。Shiro提供了对缓存的支持,支持多种缓存:如:ehcache,还支持缓存数据库:Redis。
(8)Cryptogarphy:加密。提供了常见的一些加密算法,使得在应用中可以很方便的实现数据安全,并且使用很便捷。
(9)Realm:Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取响应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;也可以把Realm看成DataSource。也是Shiro和数据库之间的桥梁。
环境搭建
<!--配置shiro核心包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!--junit包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
Shiro认证
认证过程
代码演示
public class TestShiro {
//创建Realm对象,充当数据源
SimpleAccountRealm realm = new SimpleAccountRealm();
@Before
public void addData(){
//存放原始数据
realm.addAccount("andy","123456");
}
//认证
@Test
public void testAuthenticator(){
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置SerurityManager
SecurityUtils.setSecurityManager(defaultSecurityManager);
//设置realm
defaultSecurityManager.setRealm(realm);
//获取用户
Subject subject = SecurityUtils.getSubject();
//根据用户提交的数据获取token
UsernamePasswordToken token = new UsernamePasswordToken("andy","123456");
//数据认证
subject.login(token);
//获取认证结果
System.out.println("isAuthenticated:"+subject.isAuthenticated());
//登出
subject.logout();
System.out.println("登出后isAuthenticated:"+subject.isAuthenticated());
}
输出结果
Shiro授权
代码演示
public class TestShiro {
//创建Realm对象,充当数据源
SimpleAccountRealm realm = new SimpleAccountRealm();
@Before//测试授权
public void addUser2(){
realm.addAccount("xiaoming","123456","admin","user");
}
//授权
@Test
public void testAuthorizer(){
//构建Security
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置数据源
defaultSecurityManager.setRealm(realm);
//设置Securitymanager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取用户
Subject subject = SecurityUtils.getSubject();
//根据用户提交的数据获取Token
UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123456");
//数据认证
subject.login(token);
if(subject.isAuthenticated()){
//角色认证
//subject.checkRole("user");
subject.checkRoles("user","admin");
System.out.println("角色验证通过");
}
}
输出结果
Shiro权限认证
在resources下创建user.ini
[users]
xiaoming=123456,admin
[roles]
admin=user:delete,user:update
代码演示
package com.cboy.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
public class TestShiro2 {
//创建Realm模拟数据源,引入
IniRealm iniRealm = new IniRealm("classpath:user.ini");
@Test
public void testAuthorizer(){
//构建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//引入数据源
defaultSecurityManager.setRealm(iniRealm);
//设置SecurityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//创建"用户"
Subject subject = SecurityUtils.getSubject();
//获取用户传来的数据,创建token与数据源中做对比
UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123456");
//认证
subject.login(token);
System.out.println("isAuthenticated:"+subject.isAuthenticated());
//subject.isAuthenticated()如果正确返回true
if(subject.isAuthenticated()){
//检查角色
subject.checkRoles("admin");
//检查权限
subject.checkPermission("user:delete");
System.out.println("授权成功");
}
}
}
输出结果
链接数据库操作
导入mysql与druid的jar包坐标信息
<!-- MySQL的驱动jar -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<!-- druid连接池的依赖jar-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
数据库表数据:
代码演示:
package com.cboy.test;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
public class TestShirojdbc {
//使用druid连接池,连接数据源
DruidDataSource dataSource = new DruidDataSource();
//代码块,不用加@Before注解,在初始化时自动加载
{
//配置数据源
dataSource.setUrl("jdbc:mysql://localhost:3306/shirotest");
dataSource.setUsername("root");
dataSource.setPassword("123456");
}
@Test
public void testAuthorizer(){
//创建数据源
JdbcRealm jdbcRealm = new JdbcRealm();
//将数据源写入
jdbcRealm.setDataSource(dataSource);
//将查询权限的权限打开,默认为false关闭
jdbcRealm.setPermissionsLookupEnabled(true);
//设置查询角色的sql语句,用于认证
String sql_user = "select password from shiro_users where username=?";
//执行自定义认证的sql
jdbcRealm.setAuthenticationQuery(sql_user);
//设置查询角色的sql语句,用于角色认证
String sql_roles = "select role_name from user_roles where username = ?";
//执行角色认证
jdbcRealm.setUserRolesQuery(sql_roles);
//设置查询权限的sql语句,用于查询权限
String sql_permissions = "select permission from roles_permissions where role_name = ?";
//执行权限认证
jdbcRealm.setPermissionsQuery(sql_permissions);
//构造SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//存入数据源
defaultSecurityManager.setRealm(jdbcRealm);
//设置SecurityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取用户
Subject subject = SecurityUtils.getSubject();
//模拟前台传来的数据
UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123456");
//认证
subject.login(token);
//打印是否认证成功
System.out.println("isAuthenticated:"+subject.isAuthenticated());
//判断是否成功,进行后续操作
if(subject.isAuthenticated()){
subject.checkRole("admin");
System.out.println("角色认证通过");
subject.checkPermission("user:delete");
System.out.println("权限认证通过");
}
}
}
输出结果:
Shiro自定义Realm+加密加盐
自定义realm
package com.cboy.test;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义Realm
*/
public class CustomRealm extends AuthorizingRealm {
Map<String,String> userMap = new HashMap<String, String>();
{
//不加密
//userMap.put("andy","123456");
//加密
//userMap.put("andy","e10adc3949ba59abbe56e057f20f883e");
//加盐
userMap.put("andy","48e231e66ff8943db0f6d2b6cb6536d2");
super.setName("安迪");
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//自定义认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.从主体传来的信息中获取用户名
String username = (String)authenticationToken.getPrincipal();
//2.通过用户名从数据库中获取凭证
String password = getPassWordbyUsername(username);
//如果没有查到
if(password==null){
return null;
}
//设置盐值
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("andy",password,"安迪");
//设置盐值
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("xiaoming"));
return authenticationInfo;
}
//模拟读取数据
private String getPassWordbyUsername(String username){
return userMap.get(username);
}
//计算加密后的值
public static void main(String[] args) {
//加密
// Md5Hash md5 = new Md5Hash("123456");
//加盐
Md5Hash md5 = new Md5Hash("123456","xiaoming");
System.out.println(md5);
}
}
测试
package com.cboy.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
public class TestShirozdy {
@Test
public void testShirozdy(){
//配置数据源
CustomRealm customRealm = new CustomRealm();
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置数据源
defaultSecurityManager.setRealm(customRealm);
//创建加密对象
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//加密名称
matcher.setHashAlgorithmName("md5");
//加密次数
matcher.setHashIterations(1);
//在Realm中设置加密对象
customRealm.setCredentialsMatcher(matcher);
//设置SerurityManager
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取用户
Subject subject = SecurityUtils.getSubject();
//根据用户提交的数据获取token
UsernamePasswordToken token = new UsernamePasswordToken("andy","123456");
//数据认证
subject.login(token);
//获取认证结果
System.out.println("isAuthenticated:"+subject.isAuthenticated());
}
}