diff --git a/source/_posts/shiro-spring.md b/source/_posts/shiro-spring.md
index 9b2c676..beb61e3 100644
--- a/source/_posts/shiro-spring.md
+++ b/source/_posts/shiro-spring.md
@@ -107,19 +107,13 @@ Token是一个用于承载用于用户认证信息的容器,常用的Token只
```xml
org.apache.shiro
- shiro-spring
- ${shiro.spring.version}
-
-
-
- org.apache.shiro
- shiro-web
+ shiro-spring-boot-starter
${shiro.spring.version}
```
!!! 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 ""
其实对于用户认证处理最核心的就是,只要调用`subject.login(token)`时不抛出任何异常,那么用户就已经被系统认证通过了,可以在之后的操作中通过获取`Subject`实例来得到用户的相关信息。
+!!! caution ""
+ 需要注意的是,`shiro-spring-boot-starter`中对于Bean的引用大部分都是通过Bean名称的,所以如果在运行Spring应用的时候,提示缺少再买一个名称的Bean,那么可以检查一下应用中的Shiro配置,看看是不是已经定义了相应类型的Bean,但是没有使用Shiro需求的名字。这样的话可以直接给应用中的Bean重新起一个名字即可。
+
### Shiro配置
对Shiro的配置,主要是配置Shiro的处理流程,通过定义其中的关键部件,使上图中的流程完全打通。在加入其他的功能类之前,可以首先先在项目中添加一个仅有基本功能的配置类。
@@ -249,7 +246,7 @@ public List authenticationRealms() {
```java
@Component
-public class MultiRealmsSecurityManager extends DefaultSecurityManager {
+public class MultiRealmsSecurityManager extends DefaultWebSecurityManager {
public MultiRealmsSecurityManager(
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 {
private final MemberRepository memberRepository;
+ @PostConstruct
+ private void initRealm() {
+ super.setCredentialsMatcher(new HashedCredentialsMatcher("SHA-512"));
+ }
+
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
@@ -368,7 +373,7 @@ public class TokenStore {
@Column(nullable = false)
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")
Member member;
}
@@ -383,6 +388,11 @@ public class TokenRealm extends AuthorizingRealm {
private final MemberRepository memberRepository;
private final TokenStoreRepository storeRepository;
+ @PostConstruct
+ private void initRealm() {
+ super.setCredentialsMatcher(new SimpleCredentialsMatcher());
+ }
+
@Override
public boolean supports(AuthorizationToken token) {
return token instanceof BearerToken;
@@ -439,7 +449,7 @@ public class WebShiroConfig {
SecurityUtils.setSecurityManager(this.securityManager);
}
- @Bean
+ @Bean(name = "shiroFilterFactoryBean")
@Autowired
public ShiroFilterFactoryBean shiroFilterFactory(
ShiroFilterChainDefainition filterChainDefinition
@@ -447,10 +457,6 @@ public class WebShiroConfig {
var filterFactory = new ShiroFilterFactoryBean();
filterFactory.setSecurityManager(this.securityManager);
- Map filters = new HashMap<>();
- filters.put("bearer", bearerFilter());
- filterFactory.setFilters(filters);
-
filterFactory.setLoginUrl("/login");
filterFactory.setFilterChainDefinitionMap(filterChainDefinition.getFilterChainMap());
return filterFactory;
@@ -464,13 +470,29 @@ public class WebShiroConfig {
chainDefinition.addPathDefinition("/logout", "logout");
chainDefinition.addPathDefinition("/login", "anon");
// 要求所有需要携带用户令牌的请求都必须经过BearerHttpAuthenticationFilter
- chainDefinition.addPathDefinition("/**", "bearer");
+ chainDefinition.addPathDefinition("/**", "authcBearer");
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的示例。