版权声明:转载请注明出处 https://blog.csdn.net/cowbin2012/article/details/85266174
Shiro配置
1.Spring集成Shiro一般通过xml配置,SpringBoot集成Shiro一般通过java代码配合@Configuration和@Bean配置。
2.Shiro的核心通过过滤器Filter实现。Shiro中的Filter是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。
3.SpringBoot集成Shiro,我们需要写的主要是两个类,ShiroConfiguration类,还有继承了AuthorizingRealm的Realm类。
- ShiroConfiguration类,用来配置Shiro,注入各种Bean。包括过滤器(shiroFilter)、安全事务管理器(SecurityManager)、密码凭证(CredentialsMatcher)、aop注解支持(authorizationAttributeSourceAdvisor)等等
- Realm类,包括登陆认证(doGetAuthenticationInfo)、授权认证(doGetAuthorizationInfo)
引入依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<shiro.version>1.4.0</shiro.version>
<commons.lang.version>2.6</commons.lang.version>
<kaptcha.version>0.0.9</kaptcha.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons.lang.version}</version>
</dependency>
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
</dependencies>
编写ShiroConfiguration类
/**
* Shiro的配置文件
*/
@Configuration
public class ShiroConfig {
/**
* Session会话管理器,session交给shiro管理
*/
@Bean
public DefaultWebSessionManager sessionManager(@Value("${myframe.sessionTimeout:3600}") long globalSessionTimeout){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//是否开启会话验证器,默认是开启的
sessionManager.setSessionValidationSchedulerEnabled(true);
//禁止URL地标后面添加JSESSIONID
sessionManager.setSessionIdUrlRewritingEnabled(false);
//设置全局会话超时时间
sessionManager.setGlobalSessionTimeout(globalSessionTimeout * 1000);
sessionManager.setSessionValidationInterval(globalSessionTimeout * 1000);
return sessionManager;
}
/**
* 安全管理器
* @param userRealm
* @param sessionManager
* @return
*/
@Bean("securityManager")
public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
securityManager.setRememberMeManager(null);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/login.html");
shiroFilter.setUnauthorizedUrl("/");
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/public/**", "anon");
filterMap.put("/login.html", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/**", "authc");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
/**
* Shiro生命周期处理器,保证实现了Shiro内部lifecycle函数的bean执行
* @return
*/
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 启用shrio授权注解拦截方式,AOP式方法级权限检查
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
/**
* 加入注解的使用,不加入这个注解不生效 使用shiro框架提供的切面类,用于创建代理对象
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
过滤器Filter实现
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean shiroFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
//该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
registration.addInitParameter("targetFilterLifecycle", "true");
registration.setOrder(Integer.MAX_VALUE - 1);
registration.setEnabled(true);
registration.addUrlPatterns("/*");
return registration;
}
}
Realm类实现
/**
* 认证
*/
@Component
public class UserRealm extends AuthorizingRealm {
@Resource
private SysUserDao sysUserDao;
/**
* 授权(验证权限时调用)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
Long userId = user.getUserId();
//用户权限列表
Set<String> permsSet = new HashSet<>();
String perms = sysUserDao.queryAllPerms(userId);
permsSet.addAll(Arrays.asList(perms.trim().split(",")));
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
}
/**
* 认证(登录时调用)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authcToken;
//查询用户信息
SysUserEntity user = sysUserDao.selectOne(token.getUsername());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
return info;
}
}
登录实现类
**
* 登录相关
*/
@Controller
public class SysLoginController {
@Autowired
private Producer producer;
/**
* 生成验证码
* @param response
* @throws IOException
*/
@RequestMapping("captcha.jpg")
public void captcha(HttpServletResponse response)throws IOException {
response.setHeader("Cache-Control", "no-store, no-cache");
response.setContentType("image/jpeg");
//生成文字验证码
String text = producer.createText();
//生成图片验证码
BufferedImage image = producer.createImage(text);
//保存到shiro session
ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpg", out);
}
/**
* 登录
*/
@ResponseBody
@RequestMapping(value = "/sys/login", method = RequestMethod.POST)
public R login(String username, String password, String captcha) throws IllegalAccessException {
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
if(!captcha.equalsIgnoreCase(kaptcha)){
return R.error("验证码不正确");
}
try{
Subject subject = ShiroUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token);
}catch (UnknownAccountException e) {
return R.error(e.getMessage());
}catch (LockedAccountException e) {
return R.error("账号已被锁定,请联系管理员");
} catch (IncorrectCredentialsException e) {
return R.error("账号或密码不正确");
}catch (AuthenticationException e) {
return R.error("账户验证失败");
}
return R.ok();
}
/**
* 退出
*/
@RequestMapping(value = "logout", method = RequestMethod.GET)
public String logout() {
ShiroUtils.logout();
return "redirect:login.html";
}
}
权限测试类
@RestController
public class PermController {
@RequestMapping("/sysRead")
@RequiresPermissions("sys:read")
public String sysRead(){
return "you can sysRead";
}
@RequiresPermissions("sys:write")
@RequestMapping("/sysWrite")
public String sysWrite(){
return "you can sysWrite";
}
@RequiresPermissions("sys:delete")
@RequestMapping("/sysDelete")
public String sysDel(){
return "you can sysDelete";
}
}
每次访问带有@RequiresPermissions()方法时,都会进入UserRealm类的AuthorizationInfo()授权方法
另外subject.hasRole(“admin”) 或 subject.isPermitted(“admin”) 也会调用AuthorizationInfo()授权方法
登录测试(用户密码tom/123456)
权限测试