enhance:更正Shiro文章中的一些错误。

This commit is contained in:
徐涛 2021-10-20 15:41:30 +08:00
parent 3ea954c059
commit d4b083c023

View File

@ -107,19 +107,13 @@ Token是一个用于承载用于用户认证信息的容器常用的Token只
```xml ```xml
<dependency> <dependency>
<groupId>org.apache.shiro</groupId> <groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId> <artifactId>shiro-spring-boot-starter</artifactId>
<version>${shiro.spring.version}</version>
</dependency>
<!-- 如果是基于Web的应用还需要加入以下依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.spring.version}</version> <version>${shiro.spring.version}</version>
</dependency> </dependency>
``` ```
!!! info "" !!! info ""
在本文进行编写的时候,Shiro-Spring的版本是1.8.0 在本文进行编写的时候,`shiro-spring-boot-starter`的版本是1.8.0。你可能在Shiro的官方网站上看到了Shiro与Spring整合的说明但是请注意那片说明是针对Shiro与Spring应用整合的而不是用于Spring Boot应用的。另外在网上许多教程与介绍中都建议使用`shiro-spring-boot-web-starter`但是通过对Shiro源码的查看`shiro-spring-boot-web-starter`已经合并进了`shiro-spring-boot-starter`,所以直接选用最短的那个就好。
### 认证与授权功能流程 ### 认证与授权功能流程
@ -132,6 +126,9 @@ Token是一个用于承载用于用户认证信息的容器常用的Token只
!!! info "" !!! info ""
其实对于用户认证处理最核心的就是,只要调用`subject.login(token)`时不抛出任何异常,那么用户就已经被系统认证通过了,可以在之后的操作中通过获取`Subject`实例来得到用户的相关信息。 其实对于用户认证处理最核心的就是,只要调用`subject.login(token)`时不抛出任何异常,那么用户就已经被系统认证通过了,可以在之后的操作中通过获取`Subject`实例来得到用户的相关信息。
!!! caution ""
需要注意的是,`shiro-spring-boot-starter`中对于Bean的引用大部分都是通过Bean名称的所以如果在运行Spring应用的时候提示缺少再买一个名称的Bean那么可以检查一下应用中的Shiro配置看看是不是已经定义了相应类型的Bean但是没有使用Shiro需求的名字。这样的话可以直接给应用中的Bean重新起一个名字即可。
### Shiro配置 ### Shiro配置
对Shiro的配置主要是配置Shiro的处理流程通过定义其中的关键部件使上图中的流程完全打通。在加入其他的功能类之前可以首先先在项目中添加一个仅有基本功能的配置类。 对Shiro的配置主要是配置Shiro的处理流程通过定义其中的关键部件使上图中的流程完全打通。在加入其他的功能类之前可以首先先在项目中添加一个仅有基本功能的配置类。
@ -249,7 +246,7 @@ public List<Realm> authenticationRealms() {
```java ```java
@Component @Component
public class MultiRealmsSecurityManager extends DefaultSecurityManager { public class MultiRealmsSecurityManager extends DefaultWebSecurityManager {
public MultiRealmsSecurityManager( public MultiRealmsSecurityManager(
SubjectDAO subjectDAO, SubjectDAO subjectDAO,
@ -270,6 +267,9 @@ public class MultiRealmsSecurityManager extends DefaultSecurityManager {
} }
``` ```
!!! info ""
因为所构建的应用是一个提供Web服务的应用所以需要继承`DefaultWebSecurityManager`来提供对于Web的安全控制。
#### 构建对用户名与密码的验证 #### 构建对用户名与密码的验证
首先假设应用中的用户表结构是如下面这样定义的。 首先假设应用中的用户表结构是如下面这样定义的。
@ -321,6 +321,11 @@ public class Member {
public class UsernameRealm extends AuthoringRealm { public class UsernameRealm extends AuthoringRealm {
private final MemberRepository memberRepository; private final MemberRepository memberRepository;
@PostConstruct
private void initRealm() {
super.setCredentialsMatcher(new HashedCredentialsMatcher("SHA-512"));
}
@Override @Override
public boolean supports(AuthenticationToken token) { public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken; return token instanceof UsernamePasswordToken;
@ -368,7 +373,7 @@ public class TokenStore {
@Column(nullable = false) @Column(nullable = false)
LocalDateTime expiresAt; LocalDateTime expiresAt;
@OneToOne(targetEntity = Member.class, fetch = FetchType.LAZY, cascade = CascadeType.MERGE) @OneToOne(targetEntity = Member.class, fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
@JoinColumn(name = "mid") @JoinColumn(name = "mid")
Member member; Member member;
} }
@ -383,6 +388,11 @@ public class TokenRealm extends AuthorizingRealm {
private final MemberRepository memberRepository; private final MemberRepository memberRepository;
private final TokenStoreRepository storeRepository; private final TokenStoreRepository storeRepository;
@PostConstruct
private void initRealm() {
super.setCredentialsMatcher(new SimpleCredentialsMatcher());
}
@Override @Override
public boolean supports(AuthorizationToken token) { public boolean supports(AuthorizationToken token) {
return token instanceof BearerToken; return token instanceof BearerToken;
@ -439,7 +449,7 @@ public class WebShiroConfig {
SecurityUtils.setSecurityManager(this.securityManager); SecurityUtils.setSecurityManager(this.securityManager);
} }
@Bean @Bean(name = "shiroFilterFactoryBean")
@Autowired @Autowired
public ShiroFilterFactoryBean shiroFilterFactory( public ShiroFilterFactoryBean shiroFilterFactory(
ShiroFilterChainDefainition filterChainDefinition ShiroFilterChainDefainition filterChainDefinition
@ -447,10 +457,6 @@ public class WebShiroConfig {
var filterFactory = new ShiroFilterFactoryBean(); var filterFactory = new ShiroFilterFactoryBean();
filterFactory.setSecurityManager(this.securityManager); filterFactory.setSecurityManager(this.securityManager);
Map<String, Filter> filters = new HashMap<>();
filters.put("bearer", bearerFilter());
filterFactory.setFilters(filters);
filterFactory.setLoginUrl("/login"); filterFactory.setLoginUrl("/login");
filterFactory.setFilterChainDefinitionMap(filterChainDefinition.getFilterChainMap()); filterFactory.setFilterChainDefinitionMap(filterChainDefinition.getFilterChainMap());
return filterFactory; return filterFactory;
@ -464,13 +470,29 @@ public class WebShiroConfig {
chainDefinition.addPathDefinition("/logout", "logout"); chainDefinition.addPathDefinition("/logout", "logout");
chainDefinition.addPathDefinition("/login", "anon"); chainDefinition.addPathDefinition("/login", "anon");
// 要求所有需要携带用户令牌的请求都必须经过BearerHttpAuthenticationFilter // 要求所有需要携带用户令牌的请求都必须经过BearerHttpAuthenticationFilter
chainDefinition.addPathDefinition("/**", "bearer"); chainDefinition.addPathDefinition("/**", "authcBearer");
return chainDefinition; return chainDefinition;
} }
} }
``` ```
#### 集成Shiro后常见错误的处理
##### 所有路径都报404错误
出现这种情况的原因是`shiro-spring-boot-starter`在进行自动配置的时候,没有正确的配置`DefaultAdvisorAutoProxyCreator`的Bean所以只需要在Shiro的配置类中加入这个Bean即可代码可以仿照以下Bean实例化代码添加。
```java
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
var creator = new DefaultAdvisorAutoProxyCreator();
creator.setUsePrefix(true);
return creator;
}
```
### 处理用户登录 ### 处理用户登录
用户登录主要是一个收集用户提供的认证信息并进行校验的过程在Shiro提供的Realm加持下处理用户登录的过程被简化成了只需要组装`AuthenticationToken`不必再次实现认证信息的校验的过程。以下是一个登录Controller的示例。 用户登录主要是一个收集用户提供的认证信息并进行校验的过程在Shiro提供的Realm加持下处理用户登录的过程被简化成了只需要组装`AuthenticationToken`不必再次实现认证信息的校验的过程。以下是一个登录Controller的示例。