SpringBoot入门学习(四) --- shiro安全框架,定时器,异步调用,全局日志
shiro安全框架
控制登陆,角色权限管理,身份验证,授权,会话管理,web项目
导包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
然后在src/main/resources下新建一个关于shiro的缓存配置文件ehcache-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="cacheManagerConfigFile">
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<cache name="shiro-activeSessionCache"
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
statistics="true"/>
</ehcache>
新建一个Shiro的配置文件
package top.fuly.demo.config;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import top.fuly.demo.realm.UserRealm;
@Configuration
public class ShiroConfiguration {
/**
* ShiroFilterFactoryBean 处理拦截资源文件问题。
* 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager Filter Chain定义说明
* 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
* 3、部分过滤器可指定参数,如perms,roles
*/
@Bean
public ShiroFilterFactoryBean shirFilter(org.apache.shiro.mgt.SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置静态资源允许访问
filterChainDefinitionMap.put("/user/login**", "anon"); //anon可以直接被访问
filterChainDefinitionMap.put("/user/loginAction*", "anon"); //anon可以直接被访问
//filterChainDefinitionMap.put("/js/**", "anon");
//filterChainDefinitionMap.put("/css/**", "anon");
//filterChainDefinitionMap.put("/index", "anon");
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/**", "authc"); //授权才能访问
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/user/login"); //未授权页面自动跳转到login页面
// 未授权界面;
//shiroFilterFactoryBean.setUnauthorizedUrl("/403");
Map<String, Filter> filters = new HashMap<String, Filter>();
shiroFilterFactoryBean.setFilters(filters);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public EhCacheManager getEhCacheManager() {
EhCacheManager em = new EhCacheManager();
em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return em;
}
// 开启Controller中的shiro注解
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}
/**
* 配置org.apache.shiro.web.session.mgt.DefaultWebSessionManager
*
* @return
*/
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager() {
DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
defaultWebSessionManager.setSessionDAO(getMemorySessionDAO());
defaultWebSessionManager.setGlobalSessionTimeout(4200000);
defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
defaultWebSessionManager.setSessionIdCookieEnabled(true);
defaultWebSessionManager.setSessionIdCookie(getSimpleCookie());
return defaultWebSessionManager;
}
/**
* 配置org.apache.shiro.session.mgt.eis.MemorySessionDAO
*
* @return
*/
@Bean
public MemorySessionDAO getMemorySessionDAO() {
MemorySessionDAO memorySessionDAO = new MemorySessionDAO();
memorySessionDAO.setSessionIdGenerator(javaUuidSessionIdGenerator());
return memorySessionDAO;
}
@Bean
public JavaUuidSessionIdGenerator javaUuidSessionIdGenerator() {
return new JavaUuidSessionIdGenerator();
}
/**
* session自定义cookie名
*
* @return
*/
@Bean
public SimpleCookie getSimpleCookie() {
SimpleCookie simpleCookie = new SimpleCookie();
simpleCookie.setName("security.session.id");
simpleCookie.setPath("/");
return simpleCookie;
}
@Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
dwsm.setRealm(userRealm);
// <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
dwsm.setCacheManager(getEhCacheManager());
dwsm.setSessionManager(getDefaultWebSessionManager());
return dwsm;
}
@Bean
public UserRealm userRealm(EhCacheManager cacheManager) {
UserRealm userRealm = new UserRealm();
userRealm.setCacheManager(cacheManager);
return userRealm;
}
/**
* 开启shrio注解支持
*
* @param userRealm
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(UserRealm userRealm) {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(getDefaultWebSecurityManager(userRealm));
return aasa;
}
}
这里是重点
filterChainDefinitionMap.put("/user/login*", "anon"); //anon可以直接被访问
filterChainDefinitionMap.put("/user/loginAction*", "anon"); //anon可以直接被访问
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/**", "authc"); //授权才能访问
shiroFilterFactoryBean.setLoginUrl("/user/login"); //未授权页面自动跳转到login页面
要创建一个UserRealm类
package top.fuly.demo.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.velocity.util.introspection.Info;
import fuly.FulyUtil;
import groovy.util.IFileNameFinder;
public class UserRealm extends AuthorizingRealm {
private static final String String = null;
private Object credentials;
//控制角色权限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
// TODO Auto-generated method stub
return null;
}
//控制登陆
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
String username = at.getPrincipal().toString();
if(username.contains("tom")){ //判断用户权限
System.out.println(username +" "+FulyUtil.getFileInfo());
// return new SimpleAuthenticationInfo(username, "", "tom");
}
return new SimpleAuthenticationInfo("1", at, "realmName");
}
}
测试
@RequestMapping("/user/loginAction")
public String loginAction(String username){
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(username, "1234");
try {
subject.login(token); //这里抛异常说明登陆失败
return "login Success";
} catch (Exception e) {
return "login Fail ";
}
}
在这边我没测出我想要的结果,但我知道了 shiro安全框架可以可以验证身份,可以验证角色.后续在实战项目中会详细用到这个的.
定时器
创建一个类,注入Spring容器
@Component
public class ScheduledTest {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate = 2000)
public void scheduled() {
System.out.println("码家学院提示你==》现在时间:" + dateFormat.format(new Date()));
}
}
在主函数上启动定时器
@SpringBootApplication
@EnableScheduling
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
然后启动就完事了
SpringBoot异步调用Async
主函数加上@EnableAsync ,需要异步的方法上面加上@Async注解
@Component
public class AsyncDemo {
@Async
public void asyncTest1(){
System.out.println(FulyUtil.getCurrentThreanName()+FulyUtil.getFileInfo());
}
@Async
public void asyncTest2(){
System.out.println(FulyUtil.getCurrentThreanName()+FulyUtil.getFileInfo());
}
@Async
public void asyncTest3(){
System.out.println(FulyUtil.getCurrentThreanName()+FulyUtil.getFileInfo());
}
}
//FulyUtil.getCurrentThreanName()+FulyUtil.getFileInfo() 线程名称 和当前所在行
调用
@RequestMapping("/hello")
public String hello() {
asyncDemo.asyncTest1();
asyncDemo.asyncTest2();
asyncDemo.asyncTest3();
System.out.println(FulyUtil.getCurrentThreanName()+FulyUtil.getFileInfo());
return "Hello Springboot";
}
测试读取自定义配置参数
就是读取application.properties中我们自定义的参数
如在application.properties定义参数
name=tom
则在程序中读取应为(spring会将name的值自动注入用Value注解的地方)
@Value("${name}")
private String name;
全局日志
导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
创建一个Aspect类
package top.fuly.demo.Log;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class LogAspect {
private Logger log = LoggerFactory.getLogger(getClass());
@Pointcut("execution(public * top.fuly.demo.controller..*.*(..))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
log.info("URL : " + request.getRequestURL().toString());
log.info("HTTP_METHOD : " + request.getMethod());
log.info("IP : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
log.info("name:{},value:{}", name, request.getParameter(name));
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
log.info("RESPONSE : " + ret);
}
}
重点是:
@Pointcut(“execution(public * top.fuly.demo.controller….(…))”) 不要配置错误;
上面这段注解的意思如下:
- execution(): 表达式主体
- 第一个public *号:表示返回类型, *号表示所有的类型。
- 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,top.fuly.demo.controller…包、子孙包下所有类的方法。
- 第二个*号:表示类名,*号表示所有的类。
- *(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
参考链接:https://www.cnblogs.com/30go/p/8443522.html
运行起来测试: