java程序里面的shiro.docx

上传人:b****6 文档编号:8888799 上传时间:2023-02-02 格式:DOCX 页数:42 大小:1.51MB
下载 相关 举报
java程序里面的shiro.docx_第1页
第1页 / 共42页
java程序里面的shiro.docx_第2页
第2页 / 共42页
java程序里面的shiro.docx_第3页
第3页 / 共42页
java程序里面的shiro.docx_第4页
第4页 / 共42页
java程序里面的shiro.docx_第5页
第5页 / 共42页
点击查看更多>>
下载资源
资源描述

java程序里面的shiro.docx

《java程序里面的shiro.docx》由会员分享,可在线阅读,更多相关《java程序里面的shiro.docx(42页珍藏版)》请在冰豆网上搜索。

java程序里面的shiro.docx

java程序里面的shiro

权限管理概念

引用:

权限管理是系统的安全范畴,要求必须是合法的用户才可以访问系统(用户认证),且必须具有该资源的访问权限才可以访问该资源(授权)。

认证:

登录校验。

授权:

权限校验。

权限模型:

标准权限数据模型包括:

用户、角色、权限(包括资源和权限)、用户角色关系、角色权限关系。

权限分配:

通过UI界面方便给用户分配权限,对上边权限模型进行增、删、改、查操作。

权限控制:

基于角色的权限控制:

根据角色判断是否有操作权限,因为角色的变化性较高,如果角色修改需要修改控制代码,系统可扩展性不强。

基于资源的权限控制:

根据资源权限判断是否有操作权限,因为资源较为固定,如果角色修改或角色中权限修改不需要修改控制代码,使用此方法系统可维护性很强。

建议使用。

权限管理的解决方案:

⏹对于粗颗粒权限管理,建议在系统架构层面去解决,写系统架构级别统一代码(基础代码)。

粗颗粒权限:

比如对系统的url、菜单、jsp页面、页面上按钮、类方法进行权限管理,即对资源类型进行权限管理。

⏹对于细颗粒权限管理:

粗颗粒权限:

比如用户id为001的用户信息(资源实例)、类型为t01的商品信息(资源实例),对资源实例进行权限管理,理解对数据级别的权限管理。

细颗粒权限管理是系统的业务逻辑,业务逻辑代码不方便抽取统一代码,建议在系统业务层进行处理。

基于url的权限管理(掌握):

企业开发常用的方法,使用web应用中filter来实现,用户请求url,通过filter拦截,判断用户身份是否合法(用户认证),判断请求的地址是否是用户权限范围内的url(授权)。

shiro概念

权限管理要干的事总体上可以看成2部分,一部分是用户、角色、资源,及它们的关联关系的维护。

二是认证(登录认证:

登录时验证用户名、密码;认证校验:

访问url时判断校验已经登录)、鉴权(访问url等资源时判断是否有权限),这几个常用操作。

shiro主要功能是对认证、鉴权中的某些步骤进行了封装。

登录认证流程:

1、用户输入用户名、密码,提交登录。

2、后台根据用户名查询用户账号信息。

3、对比用户传入的密码和查询返回的账号信息中的密码是否一致。

认证校验流程:

1、后台校验用户是否登录(shiro中是将已登录的subject放入session中。

取出subject进行判断)。

鉴权(校验权限)流程:

1、后台根据用户名查询用户权限。

2、对比用户请求的资源是否在用户所拥有的权限内。

(登录以后立即查询所有权限的过程,这是在准备用户菜单列表,并不是鉴权过程)

shiro对登录认证流程的第2、3步进行了封装;

对认证校验的第1步进行了封装;

对鉴权过程的第1步进行了封装(web环境中对第2步也进行了封装)。

shiro提供了AuthorizingRealm类,用户只需要实现其中的doGetAuthenticationInfo和doGetAuthorizationInfo方法即可。

登录时,将用户输入的用户名、密码封装成AuthenticationToken对象作为参数,调用doGetAuthenticationInfo方法。

查询用户时如果返回null,会自动抛出UnknownAccountException异常。

返回不为null时,shiro会自动比较传入的密码和查询返回的密码是否一致,如果不一致,会抛出IncorrectCredentialsException异常。

鉴权时,将用户名封装成PrincipalCollection对象作为参数,调用doGetAuthorizationInfo方法,返回一个AuthorizationInfo,不像认证过程的自动比对密码,这里不会自动比对权限,而是交给用户自己判断,因为权限有很多种比对方式,如全部包含、部分包含等各种情况(web环境会自动比对权限)。

shiro配置

1、pom.xml引入依赖:

junit

junit

4.12

test

org.apache.shiro

shiro-core

1.4.0

commons-logging

commons-logging

1.2

2、新建shiro_custom.ini放到classpath下:

内容:

customRealm=com.test.shiroTest.realms.MyRealm

securityManager.realms=$customRealm

 

这里类似于spring配置,通过$符号引用上面的customRealm。

3、log4j.properties放到classpath下:

内容:

log4j.rootLogger=debug,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d%p[%c]-%m%n

4、新建自定义Realm文件MyRealm.java

自定义realm一般继承AuthorizingRealm

MyRealm.java

importjava.util.ArrayList;

importjava.util.List;

importorg.apache.shiro.authc.AuthenticationException;

importorg.apache.shiro.authc.AuthenticationInfo;

importorg.apache.shiro.authc.AuthenticationToken;

importorg.apache.shiro.authc.SimpleAuthenticationInfo;

importorg.apache.shiro.authz.AuthorizationInfo;

importorg.apache.shiro.authz.SimpleAuthorizationInfo;

importorg.apache.shiro.realm.AuthorizingRealm;

importorg.apache.shiro.subject.PrincipalCollection;

publicclassMyRealmextendsAuthorizingRealm{

@Override

protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokentoken)throwsAuthenticationException{

System.out.println("--------------doGetAuthenticationInfo--------------");

//模拟查找用户

if(!

",zhangsan,lisi,wangwu,".contains(token.getPrincipal().toString())){

//返回null表示没有找到用户

returnnull;

}

//模拟数据库查询出的密码

Stringpassword="123456";

//返回认证信息

SimpleAuthenticationInfosimpleAuthenticationInfo=newSimpleAuthenticationInfo("zhangsan",password,"MyRealm");

returnsimpleAuthenticationInfo;

}

@Override

protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){

System.out.println("--------------doGetAuthorizationInfo--------------");

//获取身份信息

Stringusername=(String)principals.getPrimaryPrincipal();

//根据身份信息从数据库中查询权限数据

//....这里使用静态数据模拟

Listpermissions=newArrayList();

permissions.add("user:

create");

permissions.add("user:

delete");

//将权限信息封装装为AuthorizationInfo

SimpleAuthorizationInfosimpleAuthorizationInfo=newSimpleAuthorizationInfo();

for(Stringpermission:

permissions){

simpleAuthorizationInfo.addStringPermission(permission);

}

returnsimpleAuthorizationInfo;

}

}

5、创建测试程序:

AuthenticationTest.java:

importjava.util.Arrays;

importorg.apache.shiro.SecurityUtils;

importorg.apache.shiro.authc.AuthenticationException;

importorg.apache.shiro.authc.UsernamePasswordToken;

importorg.apache.shiro.config.IniSecurityManagerFactory;

importorg.apache.shiro.mgt.SecurityManager;

importorg.apache.shiro.subject.Subject;

importorg.apache.shiro.util.Factory;

importorg.junit.Test;

publicclassAuthenticationTest{

@Test

publicvoidtest2(){

//从ini文件中创建SecurityManager工厂

Factoryfactory=newIniSecurityManagerFactory("classpath:

shiro_custom.ini");

//创建SecurityManager

SecurityManagersecurityManager=factory.getInstance();

//将securityManager设置到运行环境

SecurityUtils.setSecurityManager(securityManager);

//创建主体对象

Subjectsubject=SecurityUtils.getSubject();

//对主体对象进行认证

//用户登陆

//设置用户认证的身份(principals)和凭证(credentials)

UsernamePasswordTokentoken=newUsernamePasswordToken("zhangsan","123456");

try{

subject.login(token);

}catch(AuthenticationExceptione){

e.printStackTrace();

}

//用户认证状态

BooleanisAuthenticated=subject.isAuthenticated();

System.out.println("用户认证状态:

"+isAuthenticated);

//用户授权检测基于角色授权

//是否有某一个角色

System.out.println("用户是否拥有一个角色:

"+subject.hasRole("role1"));

//是否有多个角色

System.out.println("用户是否拥有多个角色:

"+subject.hasAllRoles(Arrays.asList("role1","role2")));

//subject.checkRole("role1");

//subject.checkRoles(Arrays.asList("role1","role2"));

//授权检测,失败则抛出异常

//subject.checkRole("role22");

//基于资源授权

System.out.println("是否拥有某一个权限:

"+subject.isPermitted("user:

delete"));

System.out.println("是否拥有多个权限:

"+subject.isPermittedAll("user:

create:

1","user:

delete"));

////检查权限

//subject.checkPermission("sys:

user:

delete");

//subject.checkPermissions("user:

create:

1","user:

delete");

}

}

输出:

使用IniRealm:

当使用IniRealm时,它自己实现了doGetAuthenticationInfo方法和doGetAuthorizationInfo方法,认证时,它会到配置文件中查找用户,返回含有密码的AuthenticationInfo。

,鉴权时,它会从配置文件中去查询用户权限返回。

因此IniRealm可以看成了自定义Realm的一个实现特例。

使用配置:

不需要新建Realm类了。

1、新建shiro.ini,内容:

[users]

#用户zhang的密码是123,此用户具有role1和role2两个角色

zhang=123,role1,role2

wang=123,role2

[roles]

#角色role1对资源user拥有create、update权限

role1=user:

create,user:

update

#角色role2对资源user拥有create、delete权限

role2=user:

create,user:

delete

#角色role3对资源user拥有create权限

role3=user:

create

2、认证的测试程序同上

认证的测试程序同上,只用把ini文件改成shiro.ini即可。

如果用户不存在,login会抛异常:

如果密码不正确,会抛异常:

认证流程分析

其中的核心是securityManager。

subject其实是由securityManager创建的。

SecurityUtils.getSubject()时会调用securityManager去创建subject。

而subject的login也是调用了securityManager的login

1、调用ModularRealmAuthenticator.doAuthenticate方法。

进入securityManger.login方法,可以看到securityManager有一个Authenticator接口成员,它的实现是ModularRealmAuthenticator。

而login最终调用到了AbstractAuthenticator的authenticate方法上

AbstractAuthenticator的doAuthenticate是个抽象方法,在ModularRealmAuthenticator实现。

2、调用AuthenticatingRealm的getAuthenticationInfo查询用户信息,如果不存在就抛异常。

(realms是ModularRealmAuthenticator的成员变量)

3、AuthenticatingRealm调用子类的doGetAuthenticationInfo方法查询用户,校验密码

进入到realm的查询里面:

它会先根据用户名去查询用户info,如果info不为null,就调用assertCredentialsMatch验证密码,验证失败就抛异常。

如果为null或者验证通过,都会返回info。

先看查询用户:

这里由于是从ini文件中读取,所以用的IniRealm。

再看验证密码:

使用散列算法(MD5)

散列算法概念

散列算法也叫Hash算法,用于将一段文本生成摘要信息,不可逆,常用的有MD5、sha等。

散列算法可以通过存储海量明文和密文对应表穷举的方式破解简单密码,因此密码最好不要设置成简单的123456、111111等。

通常会对每一个密码生成一个随机字符串salt,再将明文+salt加密,可以提高破解难度。

shiro已有封装的用salt进行MD5加密的类,如:

@Test

publicvoidtest2(){

System.out.println(newMd5Hash("111111","eteokues",1).toString());

System.out.println(newSimpleHash("MD5","111111","eteokues",1).toString());

//都输出cb571f7bd7a6f73ab004a70322b963d5

}

其中111111明文,eteokues是salt,1代表加密1次。

通过源码可以看出,Md5Hash构造函数其实调用了SimpleHash,它会根据传入的不同散列算法名字进行加密。

在realm中使用

shiro.ini配置:

#定义凭证匹配器

credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher

#散列算法

credentialsMatcher.hashAlgorithmName=md5

#散列次数

credentialsMatcher.hashIterations=1

#定义自定义realm

customRealm=com.test.shiroTest.realms.MyRealm

#将凭证匹配器注入到自定义realm上

customRealm.credentialsMatcher=$credentialsMatcher

securityManager.realms=$customRealm

其中配置了一个凭证匹配器,定义了凭证匹配器的散列算法和散列次数

然后定义一个自定义realm,然后将凭证匹配器注入到realm上。

配置凭证匹配器的原因是告诉shiro加密方式,它会将用户传入的明文password加密后同返回的SimpleAuthenticationInfo中的密码进行比对。

MyRealm.java:

importorg.apache.shiro.authc.AuthenticationException;

importorg.apache.shiro.authc.AuthenticationInfo;

importorg.apache.shiro.authc.AuthenticationToken;

importorg.apache.shiro.authc.SimpleAuthenticationInfo;

importorg.apache.shiro.authz.AuthorizationInfo;

importorg.apache.shiro.realm.AuthorizingRealm;

importorg.apache.shiro.subject.PrincipalCollection;

importorg.apache.shiro.util.ByteSource;

publicclassMyRealmextendsAuthorizingRealm{

@Override

protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){

//TODOAuto-generatedmethodstub

returnnull;

}

@Override

protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokentoken)throwsAuthenticationException{

System.out.println("userCode="+token.getPrincipal());

//模拟查找用户

if(!

"zhangsan".equals(token.getPrincipal())){

returnnull;

}

//模拟数据库查询出的密码

Stringpassword="cb571f7bd7a6f73ab004a70322b963d5";

Stringsalt="eteokues";//盐

//System.out.println(newMd5Hash("111111","eteokues",1).toString());//输出cb571f7bd7a6f73ab004a70322b963d5

//返回认证信息

SimpleAuthenticationInfosimpleAuthenticationInfo=newSimpleAuthenticationInfo("zhangsan",password,ByteSource.Util.bytes(salt),getN

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 自然景观

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1