spring boot bug(3)---访问静态资源问题

本文阐述了在Spring MVC框架中如何配置静态资源路径和使用Velocity模板引擎解决白页问题,详细介绍了设置HTTP请求地址、静态资源存放位置及Velocity框架的配置步骤。

“spring.mvc.static-path-pattern”用于阐述HTTP请求地址,而“spring.resources.static-locations”则用于描述静态资源的存放位置。

使用velocity框架,访问.vm模板的路径设置,解决访问白页问题。

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon Dec 24 10:53:56 CST 2018

There was an unexpected error (type=Internal Server Error, status=500).

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

注意最后一句,这句话是各种各样错误原因。

String fileDir=MytoutiaoApplication.class.getResource("/templates").getPath();
Properties properties=new Properties();
VelocityEngine velocityEngine=new VelocityEngine();
properties.setProperty(velocityEngine.FILE_RESOURCE_LOADER_PATH, fileDir);
velocityEngine.init();
		
//获取模板对象
Template template=velocityEngine.getTemplate("news.vm");
VelocityContext context=new VelocityContext();
context.put("name", "GY");
		
StringWriter sWriter=new StringWriter();
template.merge(context, sWriter);
		
return sWriter.toString();

详情请看:https://www.jianshu.com/p/bd5e55656dc7

<think>我们正在整合Shiro到Spring Boot 2.7.18项目,使用shiro-spring-boot-starter。 根据引用[1][2][4],我们可以通过以下步骤进行集成: 1. 添加依赖 2. 创建Shiro配置类(ShiroConfig),配置安全管理器(SecurityManager)和Realm 3. 配置Shiro的过滤器(ShiroFilterFactoryBean)以定义URL的访问控制 4. 实现自定义Realm 但是,注意引用[2]和[5]提到了一些版本兼容性和配置问题,特别是Spring Boot 2.x与Shiro的兼容性,以及可能出现的重定向循环问题。 因此,我们选择与Spring Boot 2.7.18兼容的shiro-spring-boot-starter版本。根据引用[2],Spring Boot 2.3.4使用的是shiro-spring-boot-web-starter:1.6.0,而2.7.18更高,因此我们可以尝试使用较新的版本,但要注意避免引用[5]中提到的重定向问题。 步骤: 1. 添加依赖(以1.12.0为例,但注意引用[5]提到1.9.1升级到1.12.0有问题,所以我们可以先尝试1.10.0以上但稳定的版本,比如1.11.0?但为了安全,我们也可以选择1.10.0,但需要测试。不过,根据社区反馈,1.12.0可能已经修复了一些问题,我们可以尝试并注意配置) 但是,由于Spring Boot 2.7.18相对较新,建议使用Shiro starter的最新稳定版本(如1.12.0)并注意配置。 2. 配置类:创建ShiroConfig,配置SecurityManager和ShiroFilterFactoryBean。 3. 自定义Realm:实现AuthorizingRealm。 4. 注意:引用[5]提到重定向问题,解决方案可能是自定义过滤器或者检查过滤器的配置。 具体步骤: 步骤1:在pom.xml中添加依赖 ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.12.0</version> </dependency> ``` 步骤2:创建Shiro配置类 ```java import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { // 创建自定义Realm(需要自己实现) @Bean public UserRealm userRealm() { return new UserRealm(); } // 配置安全管理器 @Bean public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); return securityManager; } // 配置Shiro过滤器 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean(); filterFactoryBean.setSecurityManager(securityManager); // 设置登录URL(如果没有登录,会跳转到此URL) filterFactoryBean.setLoginUrl("/login"); // 登录成功后跳转的URL(如果之前有访问的URL,则跳转到之前访问的URL) filterFactoryBean.setSuccessUrl("/index"); // 未授权URL filterFactoryBean.setUnauthorizedUrl("/unauthorized"); // 配置访问控制规则(顺序敏感) Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 静态资源放行 filterChainDefinitionMap.put("/static/**", "anon"); // 登录页面放行 filterChainDefinitionMap.put("/login", "anon"); // 其他请求需要认证 filterChainDefinitionMap.put("/**", "authc"); filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return filterFactoryBean; } } ``` 步骤3:实现自定义Realm ```java 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 java.util.HashSet; import java.util.Set; public class UserRealm extends AuthorizingRealm { // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取用户名 String username = (String) principals.getPrimaryPrincipal(); // 根据用户名查询角色和权限(这里模拟) Set<String> roles = new HashSet<>(); roles.add("admin"); Set<String> permissions = new HashSet<>(); permissions.add("user:add"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; } // 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 获取用户名和密码 UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); String password = new String(upToken.getPassword()); // 模拟从数据库获取用户信息 if (!"admin".equals(username)) { throw new UnknownAccountException("用户不存在"); } if (!"123456".equals(password)) { throw new IncorrectCredentialsException("密码错误"); } // 返回认证信息(用户名,密码,Realm名称) return new SimpleAuthenticationInfo(username, password, getName()); } } ``` 步骤4:创建登录控制器(示例) ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class LoginController { @GetMapping("/login") public String loginPage() { return "login"; } @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password) { Subject subject = SecurityUtils.getSubject(); try { subject.login(new UsernamePasswordToken(username, password)); return "redirect:/index"; } catch (AuthenticationException e) { // 登录失败 return "login"; } } @GetMapping("/index") public String index() { return "index"; } } ``` 注意:引用[5]提到的重定向问题,如果出现重定向循环,可能是由于未正确配置过滤器的放行规则。在配置`filterChainDefinitionMap`时,确保登录页面(如`/login`)被设置为`anon`(匿名访问)。另外,如果使用了`authc`过滤器,它会要求用户登录,如果用户未登录则跳转到`loginUrl`(即`/login`),而如果`/login`没有被放行,则又会要求登录,形成循环。因此,一定要放行登录页面和静态资源。 另外,引用[2]和[4]提到,配置安全管理器(SecurityManager)时,需要将自定义的Realm设置进去。 如果启动时遇到问题,可以检查版本兼容性。如果使用1.12.0出现问题,可以尝试降低版本(如1.10.0或1.11.0)并测试。 最后,关于引用[5]中提到的重定向次数过多问题,如果按照上述配置后仍然出现,可以尝试自定义`FormAuthenticationFilter`,但上述配置中我们使用的是`authc`,它是`FormAuthenticationFilter`的别名。如果问题依旧,可以参考引用[5]的方法,即自定义一个过滤器继承`FormAuthenticationFilter`并重写某些方法,或者检查是否配置了正确的登录URL和成功URL。 我们这里先使用标准配置,如果遇到问题再调整。 生成相关问题: 1. 如何解决Shiro在Spring Boot中的重定向循环问题? 2. Shiro中如何配置多个Realm? 3. 在Shiro中如何实现记住我功能?</think>### Spring Boot 2.7.18 集成 shiro-spring-boot-starter 指南 #### 1. 添加依赖 在 `pom.xml` 中添加最新稳定版依赖(推荐 1.12.0+): ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.12.0</version> </dependency> ``` #### 2. 配置安全管理器 创建 `ShiroConfig.java` 配置类: ```java import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfig { // 自定义 Realm 实现 @Bean public UserRealm userRealm() { return new UserRealm(); } // 配置安全管理器 @Bean public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); // 注入自定义 Realm return securityManager; } // URL 过滤规则 @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition(); chain.addPathDefinition("/static/**", "anon"); // 静态资源放行 chain.addPathDefinition("/login", "anon"); // 登录页放行 chain.addPathDefinition("/logout", "logout"); // 登出处理 chain.addPathDefinition("/**", "authc"); // 所有请求需认证 return chain; } } ``` #### 3. 实现自定义 Realm 创建 `UserRealm.java` 处理认证和授权: ```java import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class UserRealm extends AuthorizingRealm { // 认证逻辑 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); // 1. 根据 username 查询数据库获取用户信息 // 2. 如果用户不存在,抛出 UnknownAccountException // 3. 密码校验(Shiro 自动完成) return new SimpleAuthenticationInfo(username, "从数据库查询的加密密码", getName()); } // 授权逻辑 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); String username = (String) principals.getPrimaryPrincipal(); // 1. 根据用户名查询角色/权限 // 2. 添加角色和权限 info.addRole("admin"); info.addStringPermission("user:delete"); return info; } } ``` #### 4. 登录控制器示例 ```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.springframework.web.bind.annotation.PostMapping; @Controller public class LoginController { @PostMapping("/login") public String login(String username, String password) { try { UsernamePasswordToken token = new UsernamePasswordToken(username, password); SecurityUtils.getSubject().login(token); return "redirect:/index"; } catch (AuthenticationException e) { return "redirect:/login?error=1"; } } } ``` #### 5. 解决常见问题 1. **重定向循环问题**(引用[5]): - 确保登录页面 `/login` 已配置 `anon` - 在 `ShiroFilterChainDefinition` 中检查 URL 规则顺序 - 升级到 1.12.0+ 版本修复已知重定向 bug 2. **版本兼容性问题**(引用[2][4]): - Spring Boot 2.7.x 需使用 Shiro 1.10.0+ - 避免混用 `shiro-spring` 和 `shiro-spring-boot-starter` 3. **配置要点**: ```java // 正确注入方式(引用[4]) @Bean public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(userRealm); // 关键步骤 return manager; } ``` #### 6. 注解权限控制 在控制器方法上添加注解: ```java @RequiresPermissions("user:create") @PostMapping("/users") public String createUser() { ... } ``` > **重要提示**:若使用注解需在启动类添加 `@EnableGlobalMethodSecurity(prePostEnabled = true)`(引用[4])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值