我的环境
- Shiro 1.4.0
- SpringBoot 2.0.6
一、遇到的问题
在我刚写好了Realm
文件和ShiroConfig
文件,做好了自定义拦截,代码如下所示
AdminRealm.java
package com.repairsystem.realm;
import com.repairsystem.entity.Administrator;
import com.repairsystem.entity.Permission;
import com.repairsystem.entity.Role;
import com.repairsystem.service.AdministratorService;
import com.repairsystem.service.PermissionService;
import com.repairsystem.service.RoleService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author CheungChingYin
* @date 2018/11/4
* @time 21:29
*/
public class AdminRealm extends AuthorizingRealm {
@Resource
private AdministratorService adminService;
@Resource
private PermissionService permissionService;
@Resource
private RoleService roleService;
/**
* 为当前登录成功的用户授予权限和分配角色
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获得用户手机
String phoneNum = (String) principalCollection.getPrimaryPrincipal();
Administrator admin = adminService.searchAdministratorByPhoneNum(phoneNum);
Role role = roleService.searchRoleById(admin.getRoleId());
List<Permission> permissionList = permissionService.searchPermissionByRoleId(admin.getRoleId());
Set<String> roleSet = new HashSet<>();
roleSet.add(role.getRoleName());
Set<String> permissionSet = new HashSet<>();
for (Permission p : permissionList) {
permissionSet.add(p.getPermissionName());
}
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(roleSet);
authorizationInfo.setRoles(permissionSet);
return authorizationInfo;
}
/**
* 用来验证当前登录的用户,获取认证信息
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//通过Token获取管理员手机号
String adminPhoneNum = (String) authenticationToken.getPrincipal();
//根据管理员手机号查询管理员信息
Administrator admin = adminService.searchAdministratorByPhoneNum(adminPhoneNum);
if (admin != null) {
SecurityUtils.getSubject().getSession().setAttribute("admin", admin);
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(admin.getAdminPhone(), admin.getAdminPassword(), "AdminRealm");
return authcInfo;
} else {
return null;
}
}
}
ShiroConfig .java
package com.repairsystem.config;
import com.repairsystem.realm.AdminRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author CheungChingYin
* @date 2018/11/5
* @time 14:20
*/
@Configuration
public class ShiroConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(ShiroConfig.class);
@Bean
public ShiroFilterFactoryBean shiroFilter(@Qualifier("getSecurityManager") SecurityManager securityManager) {
//定义shiroFilterFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置自定义的 securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置默认登录的 URL,身份认证失败会访问该 URL
shiroFilterFactoryBean.setLoginUrl("/login");
// 设置成功之后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/main");
// 设置未授权界面,权限认证失败会访问该 URL
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// LinkedHashMap 是有序的,进行顺序拦截器配置
Map<String,String> filterChainMap = new LinkedHashMap<String, String>();
// 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
filterChainMap.put("/css/**", "anon");
filterChainMap.put("/imgs/**", "anon");
filterChainMap.put("/js/**", "anon");
filterChainMap.put("/swagger-ui.html", "anon");
filterChainMap.put("/swagger-*/**", "anon");
filterChainMap.put("/swagger-ui.html/**", "anon");
// 登录 URL 放行
filterChainMap.put("/login", "anon");
// 以“/user/admin” 开头的用户需要身份认证,authc 表示要进行身份认证
filterChainMap.put("/user/admin*", "authc");
// “/user/student” 开头的用户需要角色认证,是“admin”才允许
filterChainMap.put("/user/student*/**", "roles[admin]");
// “/user/teacher” 开头的用户需要权限认证,是“user:create”才允许
filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");
// 配置 logout 过滤器
filterChainMap.put("/logout", "logout");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
LOGGER.info("====shiroFilterFactoryBean注册完成====");
return shiroFilterFactoryBean;
}
/**
* 注入自定义Realm
*
* @return
*/
@Bean(name = "adminRealm")
public AdminRealm getAdminRealm() {
AdminRealm adminRealm = new AdminRealm();
LOGGER.info("====AdminRealm注册完成=====");
return adminRealm;
}
/**
* 注入安全管理器
*
* @return
*/
@Bean(name = "getSecurityManager")
public SecurityManager getSecurityManager(@Qualifier("adminRealm") AdminRealm adminRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(adminRealm);
LOGGER.info("====securityManager注册完成====");
return securityManager;
}
}
一切代码都没问题,SpringBoot也能够正常启动,但是我是自定义了/swagger-ui.html
是匿名访问,是不会被拦截的,当时我在浏览器输入访问/swagger-ui.html
的时候,会自动跳转到login.jsp
(注意这里),输入其他地址也是跳转回login.jsp
。
二、如何解决
请检查你的pom.xml
配置文件
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
如果你引入上面这个Shiro,请留意它的<artifactId>
标签是shiro-spring-boot-starter
,这个是配合SpringBoot的Shiro,它会自动帮你配置ShiroConfig
导致自己自定义配置失效,所以通过Maven导入Shiro应该使用以下代码
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
三、解决问题的过程
1.一开始我使用Maven导入了这个Shiro
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
运行的时候发现报上面的错误(注意红框,当时我就是没有注意红框搞了好久都不能解决问题)
然后我就上网寻找解答
发现了这个问题《springboot1.5.13集成shiro》和我遇到的问题一样,解决方法是
配置之后发现SpringBoot运行没问题
2.尝试打开没有拦截的页面
发现无论是打开什么页面,都会返回到/login.jsp
然后就开始疯狂去找问题了(没有报错的BUG最可怕了)
直到我遇到这篇文章《教你 Shiro 整合 SpringBoot,避开各种坑》
他的代码里面有这样一个注释
然后我就想了会不会是被当成了默认配置呢?
在我除去了步骤1的解决方法后发现
有一个叫做autoconfig,也就是做会SpringBoot自动帮你做默认配置,所以才会这样。于是就有了上面的解决方法。