spring boot shiro整合

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<>();
		//从数据库中获取对应权限字符串并存储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进行设置



  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值