关于凭证

定义:

       凭证又称会计凭证,是指能够用来证明经济业务事项发生、明确经济责任并据以登记账簿、具有法律效力的书面证明。

 

 

分类:

       它可以分为两大类:即原始凭证和记账凭证。所谓原始凭证,又称单据,是在经济业务事项发生或者完成时填写的,用来证明经济业务事项已经发生或者完成,以明确经济责任并用作记账原始依据的一种凭证,它是进行会计核算的重要资料。所谓记账凭证,是指会计人员根据审核无误的原始凭证及有关资料,按照经济业务事项的内容和性质加以归类,并确定会计分录,作为登记会计账簿依据的会计凭证。在整个会计核算过程中,会计凭证是第一个关口,如果使用的凭证就是虚假的或者是不合法的,那么整个会计核算就不可能是真实的。

 

 

相关:

      一、会计凭证意义和种类

  (一)会计凭证的意义

  会计凭证是记录经济业务事项发生或完成情况的书面证明,也是登记账簿的依据。

  (二)会计凭证的种类

  会计凭证按照编制的程序和用途不同,分为原始凭证和记账凭证。

  二、原始凭证

  (一)原始凭证的基本内容

  (1)名称(2)日期(3)接受单位的名称(4)经济业务的内容(5)填制单位签章(6)有关人员签章(7)凭证附件

  (二)原始凭证的填制要求

  (1)记录要真实;(2)内容要完整;(3)手续要完备;(4)书写要清楚、规范;(5)编号要连续;(6)不得随意涂改、刮擦、挖补;(7)填制要及时。

  (三)原始凭证的审核

  (1)真实性;(2)合法性;(3)合理性;(4)完整性;(5)正确性;(6)及时性。

  经审核的原始凭证应根据不同情况处理:

  1 对于完全符合要求的原始凭证,应及时据以编制记账凭证入账;

  2 对于真实、合法、合理但内容不够完整、填写有错误的原始凭证,应退回给经办人员,由其负责将有关凭证补充完整、更正错误或重开后,在办理正式会计手续。

  3 对于不真实、不合法的原始凭证,会计机构、会计人员有权不予接受,并向单位负责人报告。

  三、记账凭证

  (一)记账凭证的基本内容

  (1)名称(2)日期(3)编号(4)内容摘要(5)经济业务所涉及的会计科目及记账方向(6)金额(7)记账标记(8)附件张数(9)有关人员签章。

  (二)记账凭证的编制

  对于涉及现金银行存款之间的经济业务,一般只编制付款凭证,不编收款凭证。

  (三)记账凭证的审核

  (1)内容是否真实;(2)项目是否齐全;(3)科目是否正确;(4)金额是否正确;(5)书写是否正确。

  四、会计凭证的传递和保管

  ()会计凭证的传递

  会计凭证的传递是指从会计凭证的取得或填制时起至归档保管过程中,在单位内部有关部门和人员之间的传送程序。

  ()会计凭证的保管

会计凭证的保管是指会计凭证记账后的整理、装订、归档和存查工作。

 

 

作用:

      能够用来证明事项发生、明确责任并据法律效力的书面证明。[

<think>我们正在处理一个Shiro认证问题,用户在使用自定义的`AppToken`进行认证时遇到了`IncorrectCredentialsException`。这个异常表示提交的凭证(credentials)与预期的凭证不匹配。根据用户提供的代码,我们注意到在`doGetAuthenticationInfo`方法中,他们使用了一个`jwt`作为凭证,并且进行了如下操作: 1. 验证JWT是否过期。 2. 从JWT中解析出一个序列号(sn)。 3. 根据手机号(mobile)查询电池信息(`TbUserBatteryEntity`)。 4. 比较从JWT中解析出的sn与数据库中查询到的sn是否一致。 然而,在返回`AuthenticationInfo`时,他们使用了`new SimpleAuthenticationInfo(mobile, token, getName())`。这里,`token`是`AuthenticationToken`类型的参数,实际上就是传入的`AppToken`对象。而`SimpleAuthenticationInfo`的第二个参数应该是凭证(credentials),在Shiro的认证过程中,这个凭证会被用来和`AuthenticationToken`中的凭证(即`token.getCredentials()`)进行比较。 问题在于: - 在`SimpleAuthenticationInfo`中,我们设置的凭证是传入的`token`对象(即`AppToken`实例),而`AppToken`的`getCredentials()`方法返回的是字符串类型的token(即jwt字符串)。 - 在Shiro的认证流程中,会使用配置的`CredentialsMatcher`来比较`AuthenticationInfo`中的凭证(即我们设置的`token`对象)和`AuthenticationToken`中的凭证(即`AppToken`实例的`getCredentials()`返回的jwt字符串)。显然,一个对象(`AppToken`)和字符串(jwt)是不相等的,因此会抛出`IncorrectCredentialsException`。 解决方案: 我们需要在`SimpleAuthenticationInfo`中设置正确的凭证。在用户的业务逻辑中,实际上并没有使用传统的密码凭证,而是使用JWT进行认证。但是,Shiro仍然需要比较凭证。我们可以考虑以下两种方式: ### 方式一:使用JWT字符串作为凭证 在`SimpleAuthenticationInfo`中,我们设置从token中获取的jwt字符串作为凭证,这样在比较时,Shiro会比较两个字符串(即`AuthenticationToken`中的凭证和`AuthenticationInfo`中的凭证)是否相等。 修改`doGetAuthenticationInfo`方法最后一行: ```java return new SimpleAuthenticationInfo(mobile, jwt, getName()); ``` 注意:这里我们将凭证设置为`jwt`字符串(即从token中获取的jwt字符串)。这样,在Shiro进行凭证匹配时,它会比较`AppToken`中的`jwt`(由`getCredentials()`返回)和这里设置的`jwt`是否相等。但是,请注意,我们已经在方法中验证了JWT的有效性(未过期),所以这里直接使用jwt字符串作为凭证是可行的,因为JWT本身是自包含的,并且我们已经在前面验证了它的有效性。 ### 方式二:自定义CredentialsMatcher 如果我们不想使用字符串比较,或者有更复杂的凭证匹配逻辑(例如,我们可能希望忽略凭证比较,因为我们已经验证了JWT),我们可以自定义一个`CredentialsMatcher`,并在Realm中设置它。 1. 创建一个自定义的凭证匹配器,例如: ```java public class JwtCredentialsMatcher implements CredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { // 因为我们已经在Realm中验证了JWT的有效性,所以这里直接返回true return true; } } ``` 2. 在Realm中设置这个匹配器: ```java @Autowired private JwtCredentialsMatcher jwtCredentialsMatcher; @PostConstruct public void initCredentialsMatcher() { setCredentialsMatcher(jwtCredentialsMatcher); } ``` 然后,在`doGetAuthenticationInfo`方法中,我们可以返回任何凭证(因为匹配器总是返回true),例如: ```java return new SimpleAuthenticationInfo(mobile, token, getName()); ``` 但是,这种方式需要确保在`doGetAuthenticationInfo`方法中已经完成了所有的凭证验证(包括JWT的签名和过期时间等),因为匹配器将不再进行任何验证。 ### 推荐方案 由于用户已经在`doGetAuthenticationInfo`方法中验证了JWT的有效性(包括过期时间),并且还进行了业务相关的sn匹配,因此,我们可以采用第一种方式,即使用JWT字符串作为凭证。这样,我们不需要自定义匹配器,而且凭证匹配就是简单的字符串相等比较(实际上,在Shiro中默认使用`SimpleCredentialsMatcher`,它进行简单的相等比较)。 修改后的`doGetAuthenticationInfo`方法最后一行: ```java return new SimpleAuthenticationInfo(mobile, jwt, getName()); ``` 这样,当Shiro比较凭证时,它会比较`AppToken`中的`jwt`(即用户提交的凭证)和`AuthenticationInfo`中的`jwt`(即我们这里设置的jwt)是否相等。由于在同一个请求中,这两个字符串是相同的(都是从同一个`AppToken`中获取的),所以比较会通过。 ### 注意事项 1. 在`doGetAuthenticationInfo`方法中,我们首先验证了JWT是否过期,如果过期则抛出异常。然后,我们解析sn并进行了业务检查。这些步骤都是必要的。 2. 在返回`SimpleAuthenticationInfo`时,我们设置的凭证是`jwt`字符串,而不是整个`token`对象。 ### 完整修改后的代码 ```java @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { String mobile = (String) token.getPrincipal(); String jwt = (String) token.getCredentials(); // 1. 验证JWT签名和过期时间 if (StringUtils.isBlank(jwt) || jwtUtils.isTokenExpired(jwt)) { throw new AuthenticationException("请重新登录"); } // 2. 解析 String sn = jwtUtils.getSn(jwt); // 3. 查询 TbUserBatteryEntity result = userBatteryService.findBySnAndMobile(mobile); if (result == null) { throw new UnknownAccountException(); } if (!sn.equals(result.getSn())) { throw new RRException("电池不匹配"); } // 修改这里:将凭证设置为jwt字符串 return new SimpleAuthenticationInfo(mobile, jwt, getName()); } ``` ### 关于凭证加密的问题 在用户的问题中,他们提到“凭证是在哪里进行加密的”。从代码中可以看出,他们使用的是JWT,而JWT本身可以包含签名(使用密钥进行签名,防止篡改),但并不是加密(JWT payload默认是Base64编码,可以被解码)。如果用户需要加密JWT payload,则需要使用JWE(JSON Web Encryption)。但是,在当前的代码中,并没有体现加密,而是使用JWT的签名来验证完整性。 如果用户需要加密,可以考虑使用支持JWE的库来生成和解析JWT,并在`jwtUtils`中实现相应的加密和解密逻辑。但请注意,这通常用于保护payload中的敏感信息,而不仅仅是验证完整性。 ### 总结 用户遇到的`IncorrectCredentialsException`是由于在`SimpleAuthenticationInfo`中设置了错误的凭证(整个`token`对象)导致的。解决方案是将凭证设置为从token中获取的jwt字符串。这样,Shiro在比较凭证时就会比较两个相同的字符串,从而通过认证。 ### 相关问题 1. 如何在Shiro中集成JWT认证? 2. 如何自定义Shiro的CredentialsMatcher? 3. JWT的签名和加密有什么区别? 4. 在Shiro中如何处理自定义异常?</think>### Apache Shiro凭证加密位置与`IncorrectCredentialsException`解决方案 在Apache Shiro中,凭证加密发生在两个关键位置,而`IncorrectCredentialsException`错误通常源于凭证匹配失败。以下是完整解决方案: --- ### 一、Shiro凭证加密的核心位置 1. **数据库存储加密** - 用户密码在存入数据库前会被加密(如SHA-256/MD5) - 示例代码(基于引用[3]的`SysUser`实体): ```java public void registerUser(String username, String plainPassword) { SysUser user = new SysUser(); user.setUsername(username); // 密码加密存储 user.setPassword(DigestUtils.sha256Hex(plainPassword)); userDao.save(user); } ``` 2. **凭证匹配器加密** - `HashedCredentialsMatcher`在比较时自动加密输入凭证 - 配置示例: ```java @Bean public Realm customRealm() { CustomRealm realm = new CustomRealm(); HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("SHA-256"); // 与数据库加密算法一致 matcher.setHashIterations(1); // 哈希迭代次数 realm.setCredentialsMatcher(matcher); // 关键配置 return realm; } ``` --- ### 二、`IncorrectCredentialsException`错误修复步骤 #### 问题根源分析 在您的代码中: ```java return new SimpleAuthenticationInfo(mobile, token, getName()); ``` - 第二个参数`token`(`AppToken`对象)会被Shiro与用户输入凭证比较 - 但`AppToken.getCredentials()`返回的是JWT字符串,而数据库存储的是加密密码 #### 修复方案 1. **修改`doGetAuthenticationInfo`返回值** 返回数据库中的加密密码作为凭证: ```java @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { String mobile = (String) token.getPrincipal(); String jwt = (String) token.getCredentials(); // 验证JWT逻辑不变... // 获取用户时返回加密密码 TbUserBatteryEntity user = userBatteryService.findBySnAndMobile(mobile); return new SimpleAuthenticationInfo( mobile, user.getPassword(), // 返回数据库加密密码 getName() ); } ``` 2. **配置凭证匹配器**(关键步骤) 在Realm初始化时添加: ```java public class CustomRealm extends AuthorizingRealm { @Override public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { // 创建哈希匹配器 HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("SHA-256"); // 与注册时算法一致 super.setCredentialsMatcher(matcher); } } ``` 3. **JWT处理优化** 在认证前完成JWT验证: ```java public class JwtFilter extends AuthenticatingFilter { @Override protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String jwt = getJwtFromHeader(request); if(jwtUtils.isTokenExpired(jwt)) { throw new ExpiredCredentialsException("Token过期"); } String mobile = jwtUtils.getMobile(jwt); return new AppToken(mobile, jwt); } } ``` --- ### 三、完整工作流程 1. **用户登录** ```mermaid sequenceDiagram participant Client participant Controller participant Shiro participant DB Client->>Controller: POST /login {mobile, password} Controller->>Shiro: subject.login(new AppToken(mobile, password)) Shiro->>CustomRealm: doGetAuthenticationInfo() CustomRealm->>DB: 查询用户密码(hash) CustomRealm->>HashedCredentialsMatcher: 自动加密比较 Shiro-->>Client: 返回JWT(认证成功) ``` 2. **后续请求认证** ```mermaid sequenceDiagram participant Client participant JwtFilter participant CustomRealm Client->>JwtFilter: 携带JWT的请求 JwtFilter->>JwtUtils: 验证签名/过期 JwtFilter->>CustomRealm: 创建AppToken CustomRealm->>DB: 验证用户状态 CustomRealm->>Shiro: 返回认证信息 ``` --- ### 四、常见错误排查 1. **加密算法不一致** - 检查注册时使用的加密算法(如`SHA-256`)是否与`HashedCredentialsMatcher`配置一致 2. **凭证类型不匹配** - 确保`SimpleAuthenticationInfo`的凭证是`String`类型(加密密码) - 不是`AppToken`对象本身 3. **JWT验证位置错误** - 在`Filter`中验证JWT有效性,避免在Realm中重复验证 > 通过正确配置凭证匹配器,Shiro会自动处理加密流程,开发者无需手动比较密码[^1][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值