springboot shiro 自定义filter调用SecurityUtils.getSubject()报UnavailableSecurityManagerException

在SpringBoot集成Shiro项目中,遇到自定义Filter尝试通过SecurityUtils.getSubject()获取Subject时抛出UnavailableSecurityManagerException异常。问题关键在于自定义的CorsFilter的执行顺序。解决方案是确保CorsFilter配置在ShiroFilter之后,以正确访问session数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

框架简述:springboot+shiro

问题简述:自定义filter中要调用session存储数据,供后续方法调用。

SecurityUtils.getSubject().getSession()报UnavailableSecurityManagerException

处理方法备忘:

CorsFilter即为自定义的filter

CorsFilter要在shirofilter之后调用即可。

public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
   System.out.println("ShiroConfiguration.shirFilter()");
   ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
   Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();//获取filters
   filters.put("authc", new MyShiroSessionFilter());//将自定义 的FormAuthenticationFilter注入shiroFilter中
   //定义CorsFilter 在shirosessionfilter 之后
   filters.put("corsFilter",new CorsFilter());
   shiroFilterFactoryBean.setSecurityManager(s
Spring Boot和Shiro与前后端分离的结合可以使用RESTful API来实现。多用户可以通过Shiro的Realm来实现用户的认证和授权。下面是一个简单的示例: 1. 配置Shiro 在Spring Boot中,可以使用ShiroJava Config方式配置Shiro。 ```java @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("jwt", new JwtFilter()); shiroFilterFactoryBean.setFilters(filters); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/api/login", "anon"); filterChainDefinitionMap.put("/api/logout", "logout"); filterChainDefinitionMap.put("/**", "jwt"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(Realm realm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); return securityManager; } @Bean public Realm realm() { return new MyRealm(); } } ``` 在上面的代码中,我们配置了Shiro的过滤器,并且设置了登录URL和未授权URL。我们还配置了一个JwtFilter来验证JWT Token。最后,我们将所有URL都设置为需要通过JwtFilter才能访问。 2. 自定义Realm ```java public class MyRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); User user = userService.findByUsername(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(); User user = userService.findByUsername(username); if (user == null) { throw new UnknownAccountException(); } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); return authenticationInfo; } } ``` 在上面的代码中,我们自定义了一个Realm,用于用户的认证和授权。在认证时,我们根据用户名查询数据库,如果查询到了对应的用户,则返回一个SimpleAuthenticationInfo对象;否则抛出UnknownAccountException异常。在授权时,我们根据用户名查询数据库,然后将用户的角色和权限设置到SimpleAuthorizationInfo对象中。 3. 编写JWT Filter ```java public class JwtFilter extends AuthenticatingFilter { @Autowired private UserService userService; @Autowired private JwtUtils jwtUtils; @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String token = httpServletRequest.getHeader("Authorization"); if (StringUtils.isEmpty(token)) { throw new UnauthorizedException(); } try { Claims claims = jwtUtils.getClaimsFromToken(token); String username = claims.getSubject(); User user = userService.findByUsername(username); if (user == null) { throw new UnauthorizedException(); } JwtToken jwtToken = new JwtToken(token); getSubject(request, response).login(jwtToken); return true; } catch (Exception e) { throw new UnauthorizedException(); } } @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { return false; } } ``` 在上面的代码中,我们编写了一个JwtFilter,用于验证JWT Token。在过滤器中,我们从Header中获取Token,并解析出其中的用户名。然后根据用户名查询数据库,如果查询到了对应的用户,则创建一个JwtToken对象,调用Subject的login方法进行登录。 4. 编写Controller ```java @RestController @RequestMapping("/api") public class UserController { @Autowired private UserService userService; @PostMapping("/login") public Result login(@RequestBody User user) { User dbUser = userService.findByUsername(user.getUsername()); if (dbUser == null || !dbUser.getPassword().equals(user.getPassword())) { return Result.fail("用户名或密码错误"); } String token = JwtUtils.generateToken(dbUser.getUsername()); return Result.success(token); } @GetMapping("/user") public Result getUser() { String username = (String) SecurityUtils.getSubject().getPrincipal(); User user = userService.findByUsername(username); return Result.success(user); } @RequiresPermissions("user:add") @PostMapping("/user") public Result addUser(@RequestBody User user) { userService.addUser(user); return Result.success(); } } ``` 在上面的代码中,我们编写了一个UserController,用于处理用户相关的请求。在登录接口中,我们根据用户名和密码查询数据库,如果查询到了对应的用户,则使用JwtUtils生成一个Token并返回。在getUser接口中,我们获取当前登录的用户名,然后根据用户名查询数据库并返回用户信息。在addUser接口中,我们使用@RequiresPermissions注解来限制只有拥有user:add权限的用户才能访问该接口。 5. 测试 使用Postman等工具来测试接口,可以通过登录接口获取Token,并在后续请求中将Token加入到Header中进行访问。 以上就是Spring Boot和Shiro与前后端分离结合实现多用户认证和授权的示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值