/原创/初学者简单的shrio用法

来源:互联网 发布:淘宝网长袖连衣裙 编辑:程序博客网 时间:2024/05/29 15:37
一 Shiro简介

Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障。


Shiro的具体功能点如下:

(1)身份认证/登录,验证用户是不是拥有相应的身份; 
(2)授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限; 
(3)会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的; 
(4)加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储; 
(5)Web支持,可以非常容易的集成到Web环境; 
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率; 
(6)shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去; 
(7)提供测试支持; 
(8)允许一个用户假装为另一个用户(如果他们允许)的身份进行访问; 
(9)记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。


二 身份认证Authentication
1 工作流程



2 认证主体 Subject
Subject 认证主体包含两个信息:
Principals:身份。可以是用户名,邮件,手机号码等等,用来标识一个登录主体身份; 
Credentials:凭证。常见有密码,数字证书等等


在Shiro中可以在.ini文件中指定一个认证主体,也可以从数据库中取。
ini文件写法:
[users] 
zhangsan=12345 
lisi=12345


3 realm
realm就是一个域,Shiro就是从realm中获取验证数据的,比如,上一节中提到的.ini文件,realm有很多种,如text realm、jdbc realm、jndi realm、自定义realm等。

4 程序实现
1)在maven中引入使用的jar
<dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.5</version>
    </dependency>


2)代码:
// 读取配置文件,初始化SecurityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        // 获取securityManager实例
        SecurityManager securityManager = factory.getInstance();
        // 把securityManager实例绑定到SecurityUtils
        SecurityUtils.setSecurityManager(securityManager);
        // 创建token令牌,用户名/密码
        UsernamePasswordToken token = new UsernamePasswordToken("csdn", "123");
        // 得到当前执行的用户
        Subject currentUser = SecurityUtils.getSubject();
        try{
            // 身份认证
            currentUser.login(token);   
            System.out.println("身份认证成功!");
        }catch(AuthenticationException e){
            e.printStackTrace();
            System.out.println("身份认证失败!");
        }
        // 退出
        currentUser.logout();


5 jdbc realm
1)配置文件写法
[main]
#数据源选择的是c3p0
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://localhost:3306/db_shiro
dataSource.user=root
dataSource.password=renr1981


#定义一个jdbc的realm,取名为jdbcRealm
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm


#jdbcRealm中有个属性是dataSource,选择我们上边定义的dataSource
jdbcRealm.dataSource=$dataSource


#SecurityManager中的realm选择上面定义的jdbcRealm
securityManager.realms=$jdbcRealm


2)数据库中建立表users
users中字段为username、password
注意:表名必须为users、字段必须包括username和password,且字段名不能修改


三 自定义realm认证
如果针对相对简单的系统,使用.ini文件包括用户信息,角色信息,权限信息等是可行的。但是实际项目中,各种信息都是存放在数据库中,此时需要使用自定义realm


1 配置文件
custome_realm.ini
[main]
#自定义realm
customRealm=com.rr.realm.CustomRealm
#设置realm值,相当于注入
securityManager.realms=$customRealm


2 自定义realml类
自定义realm需要继承AuthorizingRealm类
重写如下两个方法:
doGetAuthenticationInfo()方法:用来验证当前登录的用户,获取认证信息 
doGetAuthorizationInfo()方法:用来为当前登陆成功的用户授予权限和角色(已经登陆成功了)


//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
// token表示用户输入的内容
// 1从token中取出身份信息
String userCode = (String) token.getPrincipal();


// 2根据用户输入的用户名从数据库查询对应数据,如果查询不到返回null,如果查询到,获取密码进行判断

// 本例模拟从数据库查询到密码
String password = "123";


// 3返回认证信息AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userCode, password, this.getName());


return simpleAuthenticationInfo;
}


3 测试
// 读取配置文件,初始化SecurityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(classpath:customer_realm.ini);


4 hash算法
hash(散列)算法一般用于生成一段文本的摘要信息,散列算法不可逆,不同的内容获取相同的hash值的概率非常小,通常用于对密码进行处理,提高安全性。常用的散列算法有MD5、SHA-1。
使用散列算法时,还可提供一个salt(盐)值,然后与原始内容生成摘要信息,这样做的目的是为了更安全
1)shiro中的hash处理
public static void main(String[] args) {

//原始 密码 
String source = "123";
//盐值
String salt = null;
//散列次数
int hashIterations = 1;


//构造方法中:
//第一个参数:明文,原始密码 
//第二个参数:盐值,可以使用随机数
//第三个参数:hash的次数,比如2次,相当 于md5(md5(''))
Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);

String password_md5 =  md5Hash.toString();
System.out.println(password_md5);



//另外的方式,第一个参数:指定hash算法 
SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
System.out.println(simpleHash.toString());

}




[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#hash算法
credentialsMatcher.hashAlgorithmName=md5
#次数
credentialsMatcher.hashIterations=1


customRealm=com.rr.realm.CustomRealmMd5
#设置realm的凭证匹配器
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm




三 授权Authorization
权限认证,也叫访问控制,即在应用中控制谁能访问哪些资源


1 权限认证的要素
最核心的三个要素是:权限,角色和用户
权限(permission):即操作资源的权利,比如访问某个页面,以及对某个模块的数据的添加,修改,删除,查看的权利; 
角色(role):指的是用户担任的的角色,一个角色可以有多个权限; 
用户(user):在Shiro 中,代表访问系统的用户

2 访问控制
1)基于角色的访问控制
授权过程是通过判断角色来完成的,哪个角色可以做这件事


2)基于资源(权限)的访问控制


3 程序实现
1)realm文件
#用户,role表示各个角色
[users]
Tom=123,role1,role2,role3
Jerry=123,role1,role2


#定义不同角色都拥有哪些权限
[roles]
role1=user:select
role2=user:add,user:update
role3=user.delete


2)测试代码
@Test
    public void testHasRole() {


        String configFile = "classpath:shiro_role.ini";
        String username = "csdn2";
        String password = "123";
        
        Subject currentUser = ShiroUtil.login(configFile, username, password);


        //测试hasRole
        System.out.println(currentUser.hasRole("role2")? "有role2这个角色" : "没有role2这个角色");


        //测试hasRoles
        boolean[] results = currentUser.hasRoles(Arrays.asList("role1","role2","role3"));
        System.out.println(results[0]? "有role1这个角色" : "没有role1这个角色");
        System.out.println(results[1]? "有role2这个角色" : "没有role2这个角色");
        System.out.println(results[2]? "有role3这个角色" : "没有role3这个角色");


        //测试hasAllRoles     
        System.out.println(currentUser.hasAllRoles(Arrays.asList("role1","role2","role3")));


        currentUser.logout();
}


@Test
    public void testHasPermit() {


        String configFile = "classpath:shiro_role.ini";
        String username = "csdn1";
        String password = "123";
        
        Subject currentUser = ShiroUtil.login(configFile, username, password);


        //测试hasRole
        System.out.println(currentUser.isPermitted("user:select")? "有select这个权限" : "没有select这个权限");


        //测试hasRoles
        boolean[] results = currentUser.isPermitted(new String[]{"user:select","user:add","user:update"});
        System.out.println(results[0]? "有user:select这个角色" : "没有user:select这个角色");
        System.out.println(results[1]? "有user:add这个角色" : "没有user:add这个角色");
        System.out.println(results[2]? "有user:update这个角色" : "没有user:update这个角色");


        currentUser.logout();
    }


简单的就这样,写完了大笑

原创粉丝点击