Shiro权限管理框架简单入门
shrio是Apache的强大灵活的开源安全框架
(spring官网用shiro做安全管理)
Shiro可以提供:
认证、授权、企业会话管理、安全加密
可以非常方便完成项目的权限管理模块的开发
Shiro和Spring Security的比较
Apache Shrio Spring security
简单、灵活 复杂、笨重
可以脱离Spring 不可脱离Spring
权限粒度较粗 权限粒度更细
shiro的结构图
用Shiro做安全认证的时候需要先创建SecurityManager对象
1. SecurityManager是用来提供安全服务的
2. 主体(Subject)提交请求认证到
3. SecurityManager(是通过)
4. Authenticator来进行认证的(它做认证的时候需要调用)
5. Realm验证获取认证数据(做最终的认证)
代码演示Shiro是如何做认证的
引入Shrio核心包: Shiro-core(maven官网搜索)
public class Authenticator{
//指定realm
SimpleAccountRealm simpleRealm = new SimpleAccountRealm();
@Before
public void addUser(){
simpleRealm.addAccount("libai","123456");
}
@Test
public void testAuthenticator(){
//1.构建SecurityManager环境
DefaultSecuirtyManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(simpleRealm);
//2.SecurityUtils设置securityManager环境
SecurityUtils.setSecurity(securityManager);
//3.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
//提交认证
UsernamePassToken token = new UsernamePasswordToken("libai","123456");
//登录
subject.login(token);
//是否认证
System.out.println("==="+subject.isAuthenticated());
//退出登录
subject.logout();
}
}
Shiro的授权
1.创建SecurityManager
2.主体授权
3.SecurityManager授权
4.Authorizer授权
5.Realm获取角色权限数据
代码演示Shiro的授权
public class Authenticator{
//指定realm
SimpleAccountRealm simpleRealm = new SimpleAccountRealm();
@Before
public void addUser(){
simpleRealm.addAccount("libai","123456","admin","user");
}
@Test
public void testAuthenticator(){
//1.构建SecurityManager环境
DefaultSecuirtyManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(simpleRealm);
//2.SecurityUtils设置securityManager环境
SecurityUtils.setSecurity(securityManager);
//3.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
//提交认证
UsernamePassToken token = new UsernamePasswordToken("libai","123456");
//登录
subject.login(token);
//是否认证
System.out.println("==="+subject.isAuthenticated());
//检查用户是否具备这样的角色 //授权可以看checkRole这个方法的源代码实现
//subject.checkRole("admin")
subject.checkRoles("admin","user");
}
}
Shiro的自定义Realm
内置Realm
IniRealm
JdbcRealm
代码演示内置Realm
IniRealm代码演示
public class IniRealm{
@Test
public void testIniRealm(){
//创建IniRealm
//指定文件路径classpath:user.ini(文件名user.ini)
//user.ini设置内容
[users]
//做认证
Mark=123456
//做授权,管理员拥有删除用户的权限
[roles]
admin=user:delete,user:update
IniRealm iniRealm = new IniRealm("classpath:user.ini");
//1.构建SecurityManager环境
DefaultSecuirtyManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(iniRealm);
//2.SecurityUtils设置securityManager环境
SecurityUtils.setSecurity(securityManager);
//3.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
//提交认证
UsernamePassToken token = new UsernamePasswordToken("libai","123456");
//登录
subject.login(token);
//是否认证
System.out.println("==="+subject.isAuthenticated());
//检查是否拥有授权
subject.checkRole("admin");
//检查是否拥有删除权限
subject.checkPermission("user:delete");
subject.checkPermission("user:update");
}
}
JdbcRealm代码演示
//因为jdbcRealm需要访问数据库,需要引入pom.xml加入依赖
(mysql-connector-java)和(druid(com.alibaba))
public class JdbcRealm{
DruidDataSource dataSource = new DruidDataSource();
{
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
}
@Test
public void testJdbcRealm(){
//JdbcRealm底层代码有默认的sql查询语句,所以能够查询到用户
//创建JdbcRealm
JdbcRealm jdbcRealm = new JdbcRealm();
jdbc.setDateSource(dataSource);
//设置权限的开关默认为false
jdbc.setPremissionsLookupEnable(true);
//自定义sql语句
String sql = "select password from test_user where user_name = ?";
jdbcRealm.setAuthenticationQuery(sql);
//1.构建SecurityManager环境
DefaultSecuirtyManager securityManager = new DefaultSecurityManager();
securityManager.setRealm("jdbcRealm");
//2.SecurityUtils设置securityManager环境
SecurityUtils.setSecurity(securityManager);
//3.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
//提交认证 这个地方根据用户名和密码做校验成功是因为数据库user表有这条数据
UsernamePassToken token = new UsernamePasswordToken("libai","123456");
//登录
subject.login(token);
//是否认证
System.out.println("==="+subject.isAuthenticated());
//检查是否拥有授权 这里的角色也是数据库表里面所拥有的才会成功
subject.checkRole("admin");
//检查是否拥有删除权限
subject.checkPermission("user:delete");
subject.checkPermission("user:update");
}
}
自定义Relam(需要继承AuthorizingRealm)
代码演示:
public class CustomRealm extends AuthorizingRealm{
Map userMap = new HashMap<>(16);
{
userMap.put("Mark","123456");
super.setName("customRealm");
}
//从数据库和缓存中获取角色数据
private Set getRolesByUserName(String username){
Set sets = new HashSet<>();
sets.add("admin");
sets.add("user");
return sets;
}
//从数据库和缓存中获取权限数据
private Set getPermissionsByUserName(String username){
Set sets = new HashSet<>();
sets.add("user:delete");
sets.add("user:add");
return sets;
}
//授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection){
String username = (String)principalCollection.getPrimaryPrincipal();
//从数据库和缓存中获取角色数据
Set roles = getRolesByUserName(username);
//从数据库和缓存中获取权限数据
Set permissions = getPermissionsByUserName(username);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(permissions);
simpleAuthorizationInfo.setRoles(roles);
retrun simpleAuthorizationInfo;
}
//认证方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
//1.从主体传过来的认证信息中 获得用户名
String username = (String) authenticationToken.getPrincipal();
2.通过用户名得到数据库中获取凭证
String password = getPasswordByUserName(username);
if(password==null){
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("Mark",password,"customRealm");
retrun authenticationInfo;
}
private String getPasswordByUserName(String username){
//这里本来应该调用数据库获取密码,这里为了演示方便从Map里获取
return userMap.get(username);
}
}
测试类调用自定义realm类
public class testCustomRealm{
@Test
public void testAuthenticator(){
//1.构建SecurityManager环境
DefaultSecuirtyManager securityManager = new DefaultSecurityManager();
CustomRealm customRealm = new CustomRealm();
securityManager.setRealm(customRealm);
//2.SecurityUtils设置securityManager环境
SecurityUtils.setSecurity(securityManager);
//3.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
//提交认证
UsernamePassToken token = new UsernamePasswordToken("libai","123456");
//登录
subject.login(token);
//是否认证
System.out.println("==="+subject.isAuthenticated());
//检查用户是否具备这样的角色 //授权可以看checkRole这个方法的源代码实现
//subject.checkRole("admin")
subject.checkRoles("admin","user");
subject.checkPermissions("user:delete","user:add");
}
}
##Shiro的加密(密码加密)
HashedCredentialsMatcher工具类的使用
//上面在定义Realm测试类第一步下面添加代码
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//设置算法名称 可变
matcher.setHashAlgorithmName("md5");
//设置加密次数 可变
matcher.setHashIterations(1);
//customRealm设置进来这个工具类
customRealm.setCredentialsMatcher(matcher);
//在自定义的CustomRealm获取密码的时候把该Map里面的密码由明文改为密文,提前在main函数里面用MD5把明文密码加密,加密后的密文放到Map的值里面
Md5Hash md5Hash = new Md5Hash("123456");//md5加密后得到密文
加盐的使用
//1.把改密码进行加盐防止对密码进行破解
由于md5加密密码之后的密文是固定的密文存在被解密的风险,加上盐代表把密文加上随机的字符串,大大降低被破解的风险
本案例给的是固定的盐,实际代码可以给随机的
Md5Hash md5Hash = new Md5Hash("123456","huge");
//2.然后把加盐之后的密码给Map的值
//3.在自定义CustomRealm类方法doGetAuthenticationInfo返回值之前把盐设置进去
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("huge"));