SpringBoot整合shiro之后无法加载静态资源文件问题
最近学习了一下SpringBoot之后想做了个小Demo进行登录拦截。
SpringBoot的目录结构如下
用SpringMvc拦截器进行拦截的时候
package com.myproject.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by Light on 2018-08-04.
*/
@Configuration
public class MyMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//super.addViewControllers(registry);
registry.addViewController("/").setViewName("login/login");
registry.addViewController("/login").setViewName("login/login");
registry.addViewController("/login/login").setViewName("login/login");
registry.addViewController("/index").setViewName("index");
}
//配置MVC拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//registry.addInterceptor()
//.addPathPatterns如果拦截所有请求("/**")的话。会把静态资源也拦截掉。所以需要设置不进行拦截的路径.excludePathPatterns("/",, "/login/login", "/user/login")。
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/", "/login/login", "/user/login");
}
}
但在这里我还没有发现我的前端引用静态资源没有static的问题所以我就改成不拦截所有的链接后发现可以访问静态资源。
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/index","/page/**").excludePathPatterns("/", "/login/login", "/user/login");
前端引用静态资源
<link rel="stylesheet" href="../../css/login.css" th:href="@{/login/css/login.css}" media="all"/>
后来接触了一下Shiro就想着拿SpringBoot来整合Shiro安全框架由于比较喜欢Layui的模块化和Layui略显大气的样式所以用Layui框架来作为前端框架。
SpringBoot引用Layui的WebJars。WebJars网站链接
添加Shiro与Layui的依赖包
<!-- shiro 权限控制 -->
<!-- shiro与spring 整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- thymeleaf对shiro的扩展坐标:用于对页面的Shiro标签进行控制 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!-- 引入layui前端框架 -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>layui</artifactId>
<version>2.3.0</version>
</dependency>
之前学习SpringBoot的时候是学的1.5版本与2.0版本相差有点大,一些配置类都被重新编写了名字也略有不同所以需要了解一下官网更新的内容。
我这里用的是2.0所以就不进行下面的操作了。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 指定即修改thymeleaf版本 -->
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!-- 布局功能的支持程序 thymeleaf3主程序 layout2已上版本-->
<!-- 布局功能的支持程序 thymeleaf3对应layout2版本 thymeleaf2对应layout1版本-->
<!-- 至于具体版本无所谓对应上了就行,保险起见还是用别人试过的好点 -->
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
到这里pom.xml文件就结束了
接下来进行Shiro的配置,在配置之前先说一下Shiro
Shiro
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
Shiro 的三大核心组件
Subject:即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,与当前应用交互的任何东西都是Subject,如网络爬虫等。所有的Subject都要绑定到SecurityManager上,与Subject的交互实际上是被转换为与SecurityManager的交互。
SecurityManager:即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。作用类似于SpringMVC中的DispatcherServlet,用于拦截所有请求并进行处理。
Realm:Realm是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realm来自定义的管理我们自己系统内部的权限规则。SecurityManager要验证用户,需要从Realm中获取用户。可以把Realm看做是数据源。
Shiro 的配置类 配置三大核心组件
package com.backlight.config.shiro;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
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;
/**
* Created by Light on 2018-08-18.
* Shiro的配置类
*/
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro 内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色的权限才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/", "anon");//匿名跳转登录页面
filterMap.put("/login", "anon");//匿名跳转登录页面
filterMap.put("/login/login", "anon"); //匿名跳转登录页面
filterMap.put("/static/login/**", "anon"); //匿名访问静态资源
filterMap.put("/user/login", "anon"); //匿名登录
filterMap.put("/*", "authc");//表示需要认证才可以访问
filterMap.put("/**", "authc");//表示需要认证才可以访问
filterMap.put("/*.*", "authc");//表示需要认证才可以访问
//修改调整的登录页面
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*
* @param userRealm
* @return
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
*
* @return
*/
@Bean(name = "userRealm")
public UserRealm getRealm() {
return new UserRealm();
}
/**
* 配置ShiroDialect,用于thymeleaf和shiro标签配合使用
*/
@Bean
public ShiroDialect getShiroDialect() {
return new ShiroDialect();
}
}
自定义Realm组件
package com.backlight.config.shiro;
import com.backlight.entity.Sys_user;
import com.backlight.service.Sys_userService;
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.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Created by Light on 2018-08-18.
* 自定义Realm 连接
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private Sys_userService sys_userService;
/**
* 执行授权逻辑
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
//info.addStringPermission("user:add");
//到数据库查询当前登录用户的授权字符串
//获取当前登录用户
Subject subject = SecurityUtils.getSubject();
Sys_user user = (Sys_user) subject.getPrincipal();
//获取授权设置
//Sys_user dbUser = sys_userService.findUserById(user.getUser_id());
//设置授权控制
//info.addStringPermission(dbUser.getPerms());
return info;
}
/**
* 执行认证逻辑
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken Usertoken = (UsernamePasswordToken) token;
Sys_user user = sys_userService.findByName(Usertoken.getUsername());
if (user == null) {
//用户名不存在
return null;//shiro底层会抛出UnKnowAccountException
}
//2.判断密码
return new SimpleAuthenticationInfo(user, user.getLogin_pass(), "");
}
}
启动运行后观察SpringBoot的静态资源
可以看到请求地址并没有static的http://localhost:8020/FantasyMusic/login/css/login.css而且会被Shiro拦截掉由于上面我放开了filterMap.put("/static/login/**", "anon"); //匿名访问静态资源
在路径上面加上static我是可以进行访问的。
既然请求地址并没有static
那我就将static注释掉添加了省略static之后的访问静态资源路径。
//filterMap.put("/static/login/**", "anon"); //匿名访问静态资源
//添加没有static的权限
filterMap.put("/login/**", "anon"); //匿名访问静态资源
filterMap.put("/webjars/**", "anon"); //匿名访问静态资源
运行测试。。。
至此SpringBoot整合Shiro与Layui的静态资源小问题解决了。