这个异常会发生在shiro的哪个类方法 org.apache.shiro.authc.IncorrectCredentialsException
时间: 2024-04-19 12:24:30 浏览: 159
`org.apache.shiro.authc.IncorrectCredentialsException` 是 Shiro 框架中的一个异常类,用于表示认证时凭证不正确的异常情况。
这个异常通常会在认证过程中的某个地方被抛出,具体取决于你如何使用 Shiro 进行认证。一般来说,它可能会在以下方法中被抛出:
1. `org.apache.shiro.realm.AuthenticatingRealm.doGetAuthenticationInfo(AuthenticationToken)` - 这是一个抽象方法,用于在 Realm 中实现具体的认证逻辑。当凭证不正确时,可以抛出 `IncorrectCredentialsException` 异常。
2. `org.apache.shiro.authc.AbstractAuthenticator.authenticate(AuthenticationToken)` - 这是一个抽象方法,用于在 Authenticator 中实现具体的认证逻辑。当凭证不正确时,可以抛出 `IncorrectCredentialsException` 异常。
3. 其他 Shiro 相关的类和方法中,可能会使用 `IncorrectCredentialsException` 来表示凭证不正确的情况。
请注意,具体的抛出场景取决于你的代码实现和使用方式。你可以查看你的代码中是否使用了 Shiro 的认证相关类和方法,并根据具体情况处理 `IncorrectCredentialsException` 异常。
相关问题
springboot+shiro的框架怎么写呢,我的maven是:<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.8.0</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.2</version> </dependency>
好的,对于使用 Spring Boot 和 Shiro 框架的项目,可以参照以下步骤进行搭建:
1. 在 pom.xml 文件中添加依赖:
```
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
```
其中,shiro-spring-boot-web-starter 是 Shiro 在 Spring Boot 中的集成包,java-jwt 是用于生成和解析 JWT 的库。
2. 在 application.properties 或 application.yml 文件中配置 Shiro:
```
# 配置 Shiro 的加密方式
shiro.hashAlgorithmName=md5
shiro.hashIterations=2
# 配置 JWT 的过期时间
jwt.expireTime=1800
# 配置 Shiro 的登录路径和首页路径
shiro.loginUrl=/login
shiro.successUrl=/index
# 配置 Shiro 的过滤器链
shiro.filterChainDefinitionMap= \
/static/** = anon \
/login = anon \
/logout = logout \
/** = authc
```
其中,shiro.hashAlgorithmName 和 shiro.hashIterations 是 Shiro 的加密方式,jwt.expireTime 是 JWT 的过期时间,shiro.loginUrl 和 shiro.successUrl 是 Shiro 的登录路径和首页路径,shiro.filterChainDefinitionMap 是 Shiro 的过滤器链。
3. 创建 Shiro 配置类,用于配置 Shiro 的各种组件:
```
@Configuration
public class ShiroConfig {
// 配置 SecurityManager
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm()); // 配置自定义 Realm
securityManager.setRememberMeManager(cookieRememberMeManager()); // 配置 RememberMeManager
securityManager.setSessionManager(sessionManager()); // 配置 SessionManager
return securityManager;
}
// 配置自定义 Realm
@Bean
public MyRealm myRealm() {
return new MyRealm();
}
// 配置 RememberMeManager
@Bean
public RememberMeManager cookieRememberMeManager() {
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
rememberMeManager.setCookie(rememberMeCookie());
return rememberMeManager;
}
// 配置 RememberMeCookie
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setMaxAge(86400); // 设置 Cookie 的过期时间为一天
return cookie;
}
// 配置 SessionManager
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionIdCookieEnabled(true);
sessionManager.setSessionIdUrlRewritingEnabled(false);
sessionManager.setSessionDAO(redisSessionDAO()); // 配置 RedisSessionDAO
sessionManager.setGlobalSessionTimeout(1800000); // 设置 Session 的过期时间为半小时
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
return sessionManager;
}
// 配置 RedisSessionDAO
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager()); // 配置 RedisManager
redisSessionDAO.setKeyPrefix("shiro:session:");
redisSessionDAO.setExpire(1800); // 设置 Session 的过期时间为半小时
return redisSessionDAO;
}
// 配置 RedisManager
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost("localhost");
redisManager.setPort(6379);
redisManager.setTimeout(0);
return redisManager;
}
// 配置 ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager());
factoryBean.setLoginUrl("/login");
factoryBean.setSuccessUrl("/index");
factoryBean.setUnauthorizedUrl("/unauthorized");
factoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());
return factoryBean;
}
// 配置 ShiroFilterChainDefinition
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/static/**", "anon");
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/logout", "logout");
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
}
```
其中,myRealm() 方法用于配置自定义 Realm,cookieRememberMeManager() 方法用于配置 RememberMeManager 和 RememberMeCookie,sessionManager() 方法用于配置 SessionManager 和 RedisSessionDAO,redisManager() 方法用于配置 RedisManager,shiroFilterFactoryBean() 方法用于配置 ShiroFilterFactoryBean,shiroFilterChainDefinition() 方法用于配置 ShiroFilterChainDefinition。
4. 创建自定义 Realm 类,用于实现用户的认证和授权逻辑:
```
public class MyRealm extends AuthorizingRealm {
// 配置加密方式
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
matcher.setHashIterations(2);
super.setCredentialsMatcher(matcher);
}
// 用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
String password = new String(upToken.getPassword());
// 根据用户名和密码查询用户信息
User user = userService.findByUsernameAndPassword(username, password);
if (user == null) {
throw new UnknownAccountException("用户名或密码错误");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
return info;
}
// 用户授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
// 根据用户角色查询权限信息
List<Role> roles = userService.findRolesByUsername(user.getUsername());
for (Role role : roles) {
info.addRole(role.getName());
List<Permission> permissions = role.getPermissions();
for (Permission permission : permissions) {
info.addStringPermission(permission.getName());
}
}
return info;
}
}
```
在自定义 Realm 类中,通过 setCredentialsMatcher() 方法配置加密方式,通过 doGetAuthenticationInfo() 方法实现用户的认证逻辑,通过 doGetAuthorizationInfo() 方法实现用户的授权逻辑。
5. 创建登录控制器,用于处理用户的登录和注销:
```
@Controller
public class LoginController {
@GetMapping("/login")
public String login() {
return "login";
}
@PostMapping("/login")
public String login(String username, String password, boolean rememberMe, HttpServletRequest request) {
try {
// 将用户名和密码封装成 UsernamePasswordToken 对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 设置 RememberMe
token.setRememberMe(rememberMe);
// 执行登录操作
SecurityUtils.getSubject().login(token);
return "redirect:/index";
} catch (UnknownAccountException e) {
request.setAttribute("error", "用户名不存在");
} catch (IncorrectCredentialsException e) {
request.setAttribute("error", "密码错误");
} catch (LockedAccountException e) {
request.setAttribute("error", "账号已被锁定");
} catch (AuthenticationException e) {
request.setAttribute("error", "登录失败:" + e.getMessage());
}
return "login";
}
@GetMapping("/logout")
public String logout() {
SecurityUtils.getSubject().logout();
return "redirect:/login";
}
}
```
在登录控制器中,通过 login() 方法实现用户的登录操作,通过 logout() 方法实现用户的注销操作。
6. 在页面中添加登录界面和首页,例如:
```
<!-- 登录界面 -->
<form method="post" action="/login">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" class="form-control" required>
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" id="password" name="password" class="form-control" required>
</div>
<div class="form-check">
<input type="checkbox" id="rememberMe" name="rememberMe" class="form-check-input">
<label for="rememberMe" class="form-check-label">记住我</label>
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
<!-- 首页 -->
<h1>欢迎登录</h1>
<p><a href="/logout">退出登录</a></p>
```
通过以上步骤,就可以使用 Spring Boot 和 Shiro 框架来实现用户的认证和授权了,当然,在具体实现时,还需要针对自己的业务需求进行一些调整和优化。
springboot 整合shiro
### 回答1:
Spring Boot可以很方便地整合Shiro,只需要在pom.xml中添加Shiro和Spring Boot的依赖,然后配置Shiro的相关信息即可。
1. 添加依赖
在pom.xml中添加以下依赖:
```
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
```
2. 配置Shiro
在Spring Boot的配置文件application.properties中添加Shiro的相关配置:
```
# Shiro配置
# Shiro过滤器链配置
shiro.filterChainDefinitions = /login = anon\n/** = authc
# Shiro会话管理器配置
shiro.sessionManager.globalSessionTimeout = 180000
# Shiro缓存管理器配置
shiro.cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
```
3. 编写Shiro配置类
编写一个Shiro配置类,用于配置Shiro的安全管理器、过滤器链等:
```
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setSessionManager(sessionManager());
securityManager.setCacheManager(cacheManager());
return securityManager;
}
@Bean
public ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return shiroRealm;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
}
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(180000);
sessionManager.setSessionDAO(sessionDAO());
return sessionManager;
}
@Bean
public SessionDAO sessionDAO() {
return new MemorySessionDAO();
}
@Bean
public CacheManager cacheManager() {
return new MemoryConstrainedCacheManager();
}
}
```
4. 编写ShiroRealm
编写一个ShiroRealm类,用于验证用户身份和权限:
```
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
List<Role> roles = userService.getRolesByUserId(user.getId());
for (Role role : roles) {
authorizationInfo.addRole(role.getName());
List<Permission> permissions = userService.getPermissionsByRoleId(role.getId());
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getName());
}
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
User user = userService.getUserByUsername(username);
if (user == null) {
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
```
5. 编写登录和注销功能
编写一个登录页面和一个注销功能,用于测试Shiro的整合效果:
```
@Controller
public class LoginController {
@GetMapping("/login")
public String login() {
return "login";
}
@PostMapping("/login")
public String doLogin(String username, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
return "redirect:/index";
} catch (UnknownAccountException e) {
return "redirect:/login?error=unknownAccount";
} catch (IncorrectCredentialsException e) {
return "redirect:/login?error=incorrectCredentials";
} catch (LockedAccountException e) {
return "redirect:/login?error=lockedAccount";
} catch (AuthenticationException e) {
return "redirect:/login?error=authenticationError";
}
}
@GetMapping("/logout")
public String logout() {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "redirect:/login";
}
}
```
以上就是Spring Boot整合Shiro的基本步骤,通过以上步骤可以实现基本的用户认证和授权功能。
### 回答2:
SpringBoot是一款开源的、快速构建可执行Java应用程序的框架,Shiro是一款Java的安全框架。SpringBoot整合Shiro可以为应用程序提供更强大的安全性,让我们了解如何实现SpringBoot与Shiro的整合。
首先,我们需要在pom.xml文件中引入Shiro的依赖,由于我们是基于SpringBoot实现的,因此可以使用SpringBoot提供的starter-shiro依赖,所以只需在pom.xml文件中添加以下依赖即可:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-shiro</artifactId>
</dependency>
```
接下来,我们需要配置Shiro的安全管理器,因为Shiro的默认安全管理器不支持SpringBean的注入,所以我们需要实现一个自定义的安全管理器。我们可以通过继承Shiro的DefaultWebSecurityManager类来创建一个自定义的安全管理器,这个安全管理器需要注入Shiro的Realm,并利用Spring的依赖注入机制进行配置。
```java
@Configuration
public class ShiroConfig {
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
@Bean
public SecurityManager securityManager(UserRealm userRealm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(userRealm);
return manager;
}
}
```
接下来,我们需要创建一个Shiro的Realm,并实现doGetAuthenticationInfo和doGetAuthorizationInfo方法。doGetAuthenticationInfo方法用于对用户进行认证,而doGetAuthorizationInfo方法则用于对用户进行授权。在实现这两个方法之前,我们需要借助于用户的模型类来定义用户的角色和权限信息。
```java
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取当前登录用户的用户名
String username = (String) principals.getPrimaryPrincipal();
// 获取用户的角色和权限信息
User user = userService.findUserByName(username);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(user.getRoles());
authorizationInfo.setStringPermissions(user.getPermissions());
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取用户登录信息
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
// 判断用户名和密码是否正确
User user = userService.findUserByName(username);
if (user == null || !user.getPassword().equals(password)) {
throw new IncorrectCredentialsException("账号名或密码错误");
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),getName());
return authenticationInfo;
}
}
```
最后,我们需要在Controller层处理登录和注销的请求。在登录请求中,我们需要使用Shiro的Subject对象对用户进行认证,而在注销请求中,我们需要利用Shiro的SecurityUtils工具类进行注销操作。
```java
@Controller
public class LoginController {
@PostMapping("/login")
@ResponseBody
public Result login(String username, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);
return Result.success();
} catch (UnknownAccountException e) {
return Result.fail("账号不存在");
} catch (IncorrectCredentialsException e) {
return Result.fail("账号名或密码错误");
}
}
@PostMapping("/logout")
@ResponseBody
public Result logout() {
Subject subject = SecurityUtils.getSubject();
subject.logout();
return Result.success();
}
}
```
本文介绍了在SpringBoot中如何实现Shiro的安全框架,主要包括如何配置Shiro的安全管理器、如何创建自定义的Realm以及如何在Controller层处理登录和注销的请求。通过整合Shiro,我们可以为应用程序提供更加全面和灵活的安全性。
### 回答3:
Springboot 是一个非常优秀的 Java 企业级开发框架,它凭借其简化的开发流程和强大的功能特性,成为了 Java 开发者们的首选框架。Shiro 是一个广泛应用于安全领域的 Java 安全框架,其主要用于身份认证、授权和会话管理等方面,同样备受 Java 开发者们的青睐。两者结合可以更方便地提供丰富的身份认证和授权功能。
如何使用 Springboot 整合 Shiro 呢?下面我们来逐步实现。
1. 引入 Shiro 依赖
首先,在 Springboot 工程中的 pom.xml 文件中添加 Shiro 依赖:
```
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.2</version>
</dependency>
```
2. 添加 Shiro 配置文件
在 resources 目录下添加 shiro.ini 配置文件,配置用户的权限信息和认证信息等。
3. 配置 ShiroFilterFactoryBean
在 Springboot 中,可以使用 ShiroFilterFactoryBean 定义 Shiro 的过滤操作。具体来说,在 Springboot 工程中的 configuration 包中创建 ShiroConfig 类,并添加以下代码:
```
@Bean
public ShiroFilterFactoryBean shiroFilter() {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager());
shiroFilter.setLoginUrl("/login");
shiroFilter.setUnauthorizedUrl("/error");
Map<String, String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/logout", "logout");
filterMap.put("/static/**", "anon");
filterMap.put("/login", "anon");
filterMap.put("/**", "authc");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
```
其中,setSecurityManager() 方法用于设置 Shiro 的 SecurityManager,setLoginUrl() 方法用于设置登录地址,setUnauthorizedUrl() 方法用于设置无权限时的地址。filterMap 定义了 URL 对应的访问权限,"anon" 表示匿名访问,"authc" 表示需要身份认证才能访问。
4. 创建 SecurityManager
在刚才的代码中,我们需要创建 SecurityManager 来管理 Shiro 的安全策略。具体来说,我们需要在我们创建的 ShiroConfig 类中添加以下代码:
```
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1800000);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
@Bean
public Realm realm() {
return new UserRealm();
}
```
其中,securityManager 用于管理 Shiro 的所有操作,setRealm() 方法设置 Shiro 权限认证操作的 Realm,它继承了 org.apache.shiro.realm.AuthenticatingRealm。sessionManager 用于管理 Shiro 的会话,设置 GlobalSessionTimeout 时间为 30 分钟。我们还需要创建 UserRealm 类,用于实现 Shiro 的安全操作。
5. 实现认证操作
在 UserRealm 类中,我们需要重写 doGetAuthenticationInfo() 方法,以实现用户的认证操作。具体的认证流程如下:
- 当用户请求 URL 时,Shiro 会检查用户是否登录;
- 如果用户没有登录,Shiro 会重定向到登录页;
- 用户在登录页面中输入用户名和密码,提交表单时,Shiro 会调用 Realm 类中的 doGetAuthenticationInfo() 方法来验证用户名和密码;
- 如果验证通过,Shiro 会把用户传给 SecurityManager,SecurityManager 产生一个会话(或修改会话)并返回一个 SessionID。
6. 实现授权操作
在 UserRealm 类中,我们需要重写 doGetAuthorizationInfo() 方法,以实现用户的授权操作。具体的授权流程如下:
- 在用户登录之后,Shiro 会调用 Realm 类中的 doGetAuthorizationInfo() 方法来验证用户的权限;
- Realm 类必须实现 doGetAuthorizationInfo() 方法,否则 Shiro 会认为用户没有任何权限;
- doGetAuthorizationInfo() 方法获取用户的角色和权限信息,并返回给 Shiro。
最后,我们需要在 Springboot 工程的启动类中添加 @EnableShiro 注解,以启用 Shiro 开发模式。
以上是 Springboot 整合 Shiro 的具体步骤,通过整合 Shiro,我们可以更加方便快捷地实现安全认证和授权功能,使我们的应用更加安全稳定。
阅读全文
相关推荐
















