您的位置:首页 > 编程语言 > Java开发

spring boot shiro整合

2017-12-09 16:29 627 查看
spring boot 整合shiro需要的jar

<properties>
<shiro.version>1.4.0</shiro.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-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-guice</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>${shiro.version}</version>
</dependency>
</dependencies>


shiro配置类:

package com.zyc.springboot.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
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.CookieRememberMeManager;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.DelegatingFilterProxy;

import com.zyc.springboot.shiro.MyFormAuthenticationFilter;
import com.zyc.springboot.shiro.MyRealm;

@Configuration
public class ShiroConfig {

@Bean(name = "shiroEhcacheManager")
public EhCacheManager getEhCacheManager() {
EhCacheManager em = new EhCacheManager();
em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return em;
}

@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor();
return lifecycleBeanPostProcessor;
}

@Bean(name = "sessionValidationScheduler")
public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler() {
ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
scheduler.setInterval(900000);
//scheduler.setSessionManager(defaultWebSessionManager());
return scheduler;
}

@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1);// 散列的次数,比如散列两次,相当于md5(md5(""));
return hashedCredentialsMatcher;
}

@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm,DefaultWebSessionManager defaultWebSessionManager) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(myRealm);
defaultWebSecurityManager.setCacheManager(getEhCacheManager());
defaultWebSecurityManager.setSessionManager(defaultWebSessionManager);
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
return defaultWebSecurityManager;
}

@Bean(name = "rememberMeCookie")
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// <!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}

/**
* cookie管理对象;
*
* @return
*/
@Bean(name = "rememberMeManager")
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}

@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public MyRealm myRealm() {
MyRealm myRealm = new MyRealm();
myRealm.setCacheManager(getEhCacheManager());
myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myRealm;
}

@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}

@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(defaultWebSecurityManager);
return aasa;
}

@Bean(name = "sessionManager")
public DefaultWebSessionManager defaultWebSessionManager(SessionDao sessionDao) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(18000000);
//		//url中是否显示session Id
sessionManager.setSessionIdUrlRewritingEnabled(false);
//		// 删除失效的session
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionValidationInterval(18000000);
sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler());
//设置SessionIdCookie 导致认证不成功,不从新设置新的cookie,从sessionManager获取sessionIdCookie
//sessionManager.setSessionIdCookie(simpleIdCookie());
sessionManager.getSessionIdCookie().setName("session-z-id");
sessionManager.getSessionIdCookie().setPath("/");
sessionManager.getSessionIdCookie().setMaxAge(60*60*24*7);

return sessionManager;
}

@Bean(name = "filterRegistrationBean1")
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new DelegatingFilterProxy(
"shiroFilter"));
filterRegistrationBean
.addInitParameter("targetFilterLifecycle", "true");
filterRegistrationBean.setEnabled(true);
filterRegistrationBean.addUrlPatterns("/");
return filterRegistrationBean;
}

@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(
@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
// SecurityUtils.setSecurityManager(defaultWebSecurityManager);
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/getMyJsp");
shiroFilterFactoryBean.setUnauthorizedUrl("/login");
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String, Filter> filterMap1 = shiroFilterFactoryBean.getFilters();
//自定义的filter 不能交给spring 容器管理,只能使用new 实例化filter
filterMap1.put("authc", new MyFormAuthenticationFilter());
shiroFilterFactoryBean.setFilters(filterMap1);
Map<String, String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/static/**", "anon");
filterMap.put("/logout", "logout");
filterMap.put("/login", "authc");
filterMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;

}

}
MyRealm类如下:

package com.zyc.springboot.shiro;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtils;
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.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;

import com.zyc.springboot.entity.User;

public class MyRealm extends AuthorizingRealm {

/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
//获取登录用户的信息,在认证时存储的是ShiroUser 所以得到的就是ShiroUser
//在其他地方也可通过SecurityUtils.getSubject().getPrincipals()获取用户信息
ShiroUser sysUser =  (ShiroUser) principals.getPrimaryPrincipal();
//权限字符串
List<String> permissions=new ArrayList<>();
//从数
e550
据库中获取对应权限字符串并存储permissions

//角色字符串
List<String> roles=new ArrayList<>();
//从数据库中获取对应角色字符串并存储roles

SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermissions(permissions);
simpleAuthorizationInfo.addRoles(roles);//角色类型
return simpleAuthorizationInfo;
}

/**
* 登录验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken arg0) throws AuthenticationException {
System.out.println("认证=====");
String userName=((MyAuthenticationToken) arg0).getUsername();
char[] password=((MyAuthenticationToken) arg0).getPassword();
User user=new User();//根据用户名密码获取user,这里不在连接数据库
user.setPassword("e10adc3949ba59abbe56e057f20f883e");//123456 md5加密后的值
user.setUserName("zyc");//user信息 本该从数据库中获取,这里为了简单,直接模拟

if(user==null){
throw new AuthenticationException("用户名密码错误");
}
ShiroUser shiroUser=new ShiroUser();//自定义的用户信息类,在shiro中存储使用
try {
BeanUtils.copyProperties(shiroUser, user);//user信息赋给shiroUser
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(shiroUser, user.getPassword(), this.getName());
return simpleAuthenticationInfo;
}

}
自定义filter  MyFormAuthenticationFilter如下

package com.zyc.springboot.shiro;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.core.annotation.Order;

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

// 登录失败,异常抛出
@Override
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request,
ServletResponse response) {
String className = e.getClass().getName();
if (e != null
&& !UnknownAccountException.class.getName().equals(className)
&& !IncorrectCredentialsException.class.getName().equals(
className)
&& !LockedAccountException.class.getName().equals(className)) { // 用户被锁定
e.printStackTrace(); // 非验证异常抛出
}
return super.onLoginFailure(token, e, request, response);
}

// 重写认证通过后的页面跳转,shiro会默认跳转到上一次请求的页面,不适用于iframe的框架
@Override
protected void issueSuccessRedirect(ServletRequest request,
ServletResponse response) throws Exception {
// 认证通过后的跳转地址
System.out.println("认证通过后的跳转地址"+getSuccessUrl());
WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true);
}

@Override
protected AuthenticationToken createToken(ServletRequest request,
ServletResponse response) {
System.out.println("create Token");
String username = getUsername(request);
String password = getPassword(request);
boolean remberMe = isRememberMe(request);
String host = "";
String captcha = "";
String ipAddr = "";
return new MyAuthenticationToken(username, password, remberMe, host,
captcha, ipAddr);
}
}
自定义token类如下:

package com.zyc.springboot.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;
/**
* 用来存储验证码等其他信息
* @author Administrator
*
*/
public class MyAuthenticationToken extends  UsernamePasswordToken {

/**
*
*/
private static final long serialVersionUID = -2681757716434500100L;

private String captcha;
private String ipAddr;

public MyAuthenticationToken(String username,String password,boolean rememberMe,String host,String captcha,String ipAddr) {
super(username, password, rememberMe, host);
this.captcha = captcha;
this.ipAddr=ipAddr;
}

public String getCaptcha() {
return captcha;
}

public void setCaptcha(String captcha) {
this.captcha = captcha;
}

public String getIpAddr() {
return ipAddr;
}

public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}

}
shiro登录认证调用有2种认证方式,个人理解为主动触发和被动触发,

主动触发是通过调用subject.login(token)方法如下:这种方式shiro 的/login=anon

@RequestMapping("tologin")
public String login(Model model, HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("login =======start==");
Subject subject = SecurityUtils.getSubject();
subject.login(token);
System.out.println("login ======end===");
return "login";
}
被动触发:是在shiro 的loginurl属性和登录表单的action跳转url 一致,get请求直接返回界面,post请求会调用认证 这种方式shiro 的/login=authc

@RequestMapping("login")
public String login(Model model, HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("login =======start==");
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) { // 已经登录,跳转到自己的首页
WebUtils.issueRedirect(request, response, "/getMyJsp");
return "login";
}
System.out.println("login ======end===");
return "login";
}


问题小结:

shiro 登录后,样式不显示

可能原因,shiro的filter 把样式给拦截了,注意shiro自定义的filter 不能交给spring 管理,并且要注意拦截器的顺序,shiroFilter 在其他拦截器之前

shiro 报there is no session with id []

产生此原因可能是在代码中的某个地方调用了session.invalidate(),或者shiro 的logout方法,之后又使用了request,session的方法

shiro 点击登录,或者认证成功后继续点击,总是返回到登录页面

正常情况下如果认证失败会返回登录界面,如果认证通过了返回登录界面可以查看设置sessionManager 的setSessionIdCookie()是如何设置cookie的,尽量不要创建新的cookie 而是使用sessionManager.getSessionIdCookie()获取默认的cookie进行设置
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring boot shiro