java用户的授权及验证_Java环境下shiro的测试-认证与授权

本文详细介绍了在Java环境下使用Shiro框架进行用户认证与授权的步骤。首先,通过导入Shiro核心库,配置users.ini文件进行认证测试。接着,解释了认证流程,包括token比对、SimpleAccountRealm的doGetAuthenticationInfo方法和CredentialsMatcher的doCredentialsMatch方法。文章还讲解了Shiro的关键对象,如AuthenticatingRealm和AuthorizationInfo接口。然后展示了如何自定义Realm以连接数据库获取用户信息,并使用HashedCredentialsMatcher进行加密认证。最后,文章探讨了基于角色和资源的授权,并给出了相应的API示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java环境下shiro的测试

1.导入依赖的核心jar包

org.apache.shiro

shiro-core

1.3.2

2.认证程序

2.1 构建users配置文件 xxx.ini doGetAuthenticationInfo方法从该配置文件中获取数据与token中比对

[users]

test=123456

lisi=123456

测试程序

public class TestShiro {

public static void main(String[] args) {

//获取安全管理器工厂

IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");

//获取安全管理器

SecurityManager securityManager = iniSecurityManagerFactory.getInstance();

//set认证器

SecurityUtils.setSecurityManager(securityManager);

//subject发起认证,获取subject

Subject subject = SecurityUtils.getSubject();

AuthenticationToken authenticationToken = new UsernamePasswordToken("test","123456");

//认证失败会抛出异常 密码:CredentialsException 账户:UnknownAccountException

try {

subject.login(authenticationToken);

} catch (AuthenticationException e) {

e.printStackTrace();

}

//当前subject是否认证通过

boolean authenticated = subject.isAuthenticated();

System.out.println(authenticated);

}

}

认证流程:

token携带身份和凭证信息--->subject发起认证--->SimpleAccountRealm(doGetAuthenticationInfo)获取配置文件中的用户信息---->CredentialsMatcher接口的实现类SimpleCredentialsMatcher:doCredentialsMatch方法对配置文件中的信息与token携带的信息进行比对--->认证成功或者失败。

3.Shiro框架中的关键对象:

AuthenticatingRealm //抽象类

//3.关键属性 该属性为凭证匹配器

CredentialsMatcher credentialsMatcher;

//1.该方法为抽象方法 其作用使用来获取数据

protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;

SimpleAccountRealm

//2.实现了AuthenticatingRealm抽象方法,用来获取配置文件中的用户信息,该类不做数据比对

SimpleCredentialsMatcher

//4.shiro中默认的凭证匹配器

public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

Object tokenCredentials = this.getCredentials(token);

Object accountCredentials = this.getCredentials(info);

return this.equals(tokenCredentials, accountCredentials);

}

必须要知道的类与接口,不然很难理解自定义Realm时属性为什么设置,使用哪种实现类方法等等:

以下代码或者截图贴出最重要的地方.

类继承关系

7302dc12553c35439b565d09c4aa65a3.png

3688038

AuthenticatingRealm类

abstract class AuthenticatingRealm{

//凭证匹配器 接口,其实现类做数据比对

private CredentialsMatcher credentialsMatcher;

//获取配置文件中的用户信息

protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;

}

该抽象方法返回类型AuthenticationInfo接口:

3354c26afc61719a0a7d2ba9e6d75b79.png

3688038

AuthorizingRealm类 抽象方法后面测试授权时使用

abstract class AuthorizingRealm{

//

//该抽象方法 获取数据 获取授权的数据

protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1);

}

该抽象方法返回类型AuthorizationInfo接口:

f571b8ab769d58359eb6ca8b4911e370.png

3688038

CredentialsMatcher凭证匹配器接口:

其中:SimpleCredentialsMatcher是shiro中默认的凭证匹配器,其子类Hashxxx等都是做加密认证时使用

0f19ad89bea1f8a535dfbecbe613b00f.png

3688038

4.开发自定义Realm

public class MyRealm extends AuthenticatingRealm {

//实现抽象方法doGetAuthenticationInfo

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)

throws AuthenticationException {

String principal =(String) authenticationToken.getPrincipal();

//查库取回User对象

SqlSession sqlSession = null;

try {

sqlSession = MySqlSession.getSqlSession();

} catch (IOException e) {

e.printStackTrace();

}

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

User user = mapper.queryUserByUserName(principal);

AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user.getPassword(),this.getName());

return authenticationInfo;

}

}

4.1通知shiro使用自定义realm

[main]

#自定义 realm

customRealm=com.nyist.test.MyRealm

#将realm设置到securityManager

securityManager.realms=$customRealm

注意:需要导入一个jar

commons-logging

commons-logging

1.2

5.shiro的加密认证方式

5.1.使用shiro提供的Md5Hash类为一个字符串加密进行测试

public class TestMD5 {

public static void main(String[] args) {

Md5Hash hash = new Md5Hash("123456","salt",1024);

String s = hash.toHex();

System.out.println(s);

//a18d2133f593d7b0e3ed488560404083

}

}

5.2.修改配置文件,加入凭证匹配器的相关配置

[main]

#自定义凭证匹配器

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

#凭证匹配器通知AuthenticatingRealm,由于自定义realm继承了AuthenticatingRealm,直接设置已有的MyRealm属性即可

#自定义 realm

customRealm=com.nyist.test.MyRealm

customRealm.credentialsMatcher=$hashedCredentialsMatcher

hashedCredentialsMatcher.hashAlgorithmName=MD5

hashedCredentialsMatcher.hashIterations=1024

#将realm设置到securityManager .realms使用set方式赋值

securityManager.realms=$customRealm

坑:Caused by: java.lang.IllegalStateException: Required 'hashAlgorithmName' property has not been set. This is required to execute the hashing algorithm.

HashedCredentialsMatcher类中set方法非常规,set方法为:setHashAlgorithmName

为什么这么设置凭证匹配器?

89de7b8f0b580b182f39a92a30208dd1.png

3688038

自定义MyRealm extends AuthorizingRealm,实现两个抽象方法

AuthenticationInfo doGetAuthenticationInfo()来自于AuthenticatingRealm类,获取认证数据

AuthorizationInfo doGetAuthorizationInfo()来自于AuthorizingRealm类,获取授权数据

public class MyRealm extends AuthorizingRealm {

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)

throws AuthenticationException {

String principal =(String) authenticationToken.getPrincipal();

//userDao.queryUserByUserName

SqlSession sqlSession = null;

try {

sqlSession = MySqlSession.getSqlSession();

} catch (IOException e) {

e.printStackTrace();

}

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

User user = mapper.queryUserByUserName(principal);

/*

* ByteSource.Util.bytes("salt") 盐字段来自数据库,凭证匹配器不能写死盐值

* 安全管理器可以获取到AuthenticationInfo中的盐值 对用户界面的凭证加密

* */

AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user.getPassword(),ByteSource.Util.bytes("salt"),this.getName());

return authenticationInfo;

}

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

//获取身份信息 Principal用户名、手机号、邮箱地址等 一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)

String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();

/*

* 用户----角色----权限

* 中间表 中间表

* */

//由primaryPrincipal查库--->获得角色info ---->获取权限info

SqlSession sqlSession = null;

try {

sqlSession = MySqlSession.getSqlSession();

} catch (IOException e) {

e.printStackTrace();

}

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

User user = mapper.queryUserByUserName(primaryPrincipal);

//测试基于角色的授权

/*if (primaryPrincipal.equals(user.getUsername())){

// class SimpleAuthorizationInfo implements AuthorizationInfo

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

authorizationInfo.addRole("super");

return authorizationInfo;

}*/

//测试基于资源的授权

if(primaryPrincipal.equals(user.getUsername())){

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

authorizationInfo.addStringPermission("user:delete");

authorizationInfo.addStringPermissions(Arrays.asList("admin:delete","admin:add"));

return authorizationInfo;

}

return null;

}

}

一张图看懂认证授权关系:

124532.png

64e96a7794e1d45d5d66a6e43e6ec896.png

3688038

授权的api

基于角色 //判断当前主体是否包含此角色

boolean b = subject.hasRole("super");

List list = Arrays.asList("super", "admin");

//判断当前主体是否包含某个角色

boolean[] booleans = subject.hasRoles(list);

//判断当前主体是否包含全部的角色

boolean b = subject.hasAllRoles(list);

基于资源 boolean b = subject.isPermitted("admin:delete");

String[] strs={"admin:delete", "admin:add"};

boolean[] permitted = subject.isPermitted(strs);

boolean permittedAll = subject.isPermittedAll(strs);

资源权限的标识符

权限字符串的规则是:“资源标识符:操作:资源实例标识符”,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。

例子:

用户创建权限:user:create,或user:create:*

用户修改实例001的权限:user:update:001

用户实例001的所有权限:user:*:001

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值