springboot+shiro

shiro簡介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

主要功能

三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
  Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
  SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
  Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
  从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
  Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
  在这里插入图片描述

pom配置

直接上代碼

		<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

shiro配置

(1)编写shiro配置类(基本结构)


import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * shiro配置类 
 */
@Configuration
public class ShiroConfiguration {
	@SuppressWarnings("unused")
	private final static Logger logger = LoggerFactory
			.getLogger(ShiroRealm.class);

	/**
	 * LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
	 * 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
	 * 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
	 */
	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	/**
	 * HashedCredentialsMatcher,这个类是为了对密码进行编码的, 防止密码在数据库里明码保存,当然在登陆认证的时候,
	 * 这个类也负责对form里输入的密码进行编码。
	 */
	@Bean(name = "hashedCredentialsMatcher")
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		credentialsMatcher.setHashAlgorithmName("MD5");
		credentialsMatcher.setHashIterations(2);
		credentialsMatcher.setStoredCredentialsHexEncoded(true);
		return credentialsMatcher;
	}

	// /**
	// * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
	// * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
	// */
	// @Bean(name = "ehCacheManager")
	// @DependsOn("lifecycleBeanPostProcessor")
	// public EhCacheManager ehCacheManager() {
	// return new EhCacheManager();
	// }

	/**
	 * ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。
	 * 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
	 */
	  //添加shiro内置过滤器,实现权限相关的url拦截
        /**
         * 常见过滤器:
         * anon:无需认证(登录)可以访问
         * authc:必须认证才可以访问
         * user:如果使用Remember Me的功能,可以直接访问
         * perms:该资源必须得到资源权限才可以访问
         * role:该资源必须得到角色权限才可以访问
         */
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean() {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager());

//		Map<String, Filter> filters = new LinkedHashMap<>();
//		LogoutFilter logoutFilter = new LogoutFilter();
//		logoutFilter.setRedirectUrl("/login");
//		shiroFilterFactoryBean.setFilters(filters);
		// authc
		Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
		filterChainDefinitionManager.put("/index", "anon");
		filterChainDefinitionManager.put("/login", "anon");
		filterChainDefinitionManager.put("/logto", "anon");
		// filterChainDefinitionManager.put("/user/edit/**",
		// "authc,perms[user:edit]");
		// 这里为了测试,固定写死的值,也可以从数据库或其他配置中读取,此处是用权限控制
		**//add和update都做了用戶權限攔截**
		**filterChainDefinitionManager.put("/add", "perms[user:add]");
		filterChainDefinitionManager.put("/update", "perms[user:update]");**
		
		filterChainDefinitionManager.put("/**", "authc");
		shiroFilterFactoryBean.setLoginUrl("/login");
		shiroFilterFactoryBean.setUnauthorizedUrl("/login");
		shiroFilterFactoryBean
		.setFilterChainDefinitionMap(filterChainDefinitionManager);
		return shiroFilterFactoryBean;
	}

	/**
	 * SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。 //
	 */
	@Bean(name = "securityManager")
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(shiroRealm());
		// securityManager.setCacheManager(ehCacheManager());
		return securityManager;
	}

	/**
	 * ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,
	 * 负责用户的认证和权限的处理,可以参考JdbcRealm的实现。
	 */
	@Bean(name = "shiroRealm")
	@DependsOn("lifecycleBeanPostProcessor")
	public ShiroRealm shiroRealm() {
		ShiroRealm realm = new ShiroRealm();
		// realm.setCredentialsMatcher(hashedCredentialsMatcher());
		return realm;
	}

	/**
	 * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
	 */
	@Bean
	@ConditionalOnMissingBean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
		defaultAAP.setProxyTargetClass(true);
		return defaultAAP;
	}

	/**
	 * AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,
	 * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
		aASA.setSecurityManager(securityManager());
		return aASA;
	}
}

(2)自定义Realm类

import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.foxconn.service.UserService;
public class ShiroRealm extends AuthorizingRealm {

	@Autowired
	private UserService userService;
	  /**
     * 执行授權逻辑
     */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String username = (String) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();       
       Set<String> stringSet = new HashSet();   
       //給用戶寫死的update權限,這裡可以點擊添加和更新來查看區別
        **stringSet.add("user:update");**
        info.setStringPermissions(stringSet);
        return info;
	}
  /**
     * 执行认证逻辑
     */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
		 System.out.println("-------身份认证方法--------");
	        String userName = (String) authenticationToken.getPrincipal();
	        String userPwd = new String((char[]) authenticationToken.getCredentials());
	        //根据用户名从数据库获取密码
	        String paw = userService.getUserPaw(userName);
	        if (userName == null) {
	            throw new AccountException("用户名不正确");
	        } else if (!userPwd.equals(paw )) {
	            throw new AccountException("密码不正确");
	        }
	        return new SimpleAuthenticationInfo(userName, userPwd,getName());
	}

}

頁面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>index首頁</title>
</head>
<body>
<div shiro:hasPermission="user:add">
進入用戶添加功能:<a href="add">用戶添加</a>
</div>
<div shiro:hasPermission="user:update">
進入用戶更新功能:<a href="update">用戶更新</a>
</div>
</body>
</html>

在这里插入图片描述
上圖中,點擊用戶添加和用戶更新做了頁面攔截,如果未登錄,點擊之後跳轉登錄頁面,

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Insert title here</title>
</head>
<body>add成功
</body>
</html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Insert title here</title>
</head>
<body>update成功

</body>
</html>

controller


@Controller
public class LoginController {

	@SuppressWarnings("unused")
	private Logger logger = Logger.getLogger(this.getClass());

	@RequestMapping("/login")
	public String login() {
		return "login";
	}

	@RequestMapping(value = "/logto", method = RequestMethod.POST)
	public String logto(String username, String password, HttpSession session,
			Model model) {
		UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
				username, password);
		Subject subject = SecurityUtils.getSubject();
		try {
			subject.login(usernamePasswordToken); // 完成登录
			subject.getPrincipal();
			return "index";
		} catch (Exception e) {
			model.addAttribute("msg", "用户名或密码错误");
			return "login";// 返回登录页面
		}
	}

	@RequestMapping(value = "/unauto")
	public String unauto(HttpServletRequest httpServletRequest) {
		return "unauto";
	}

	@RequestMapping("/logout")
	public String logOut(HttpSession session) {
		Subject subject = SecurityUtils.getSubject();
		subject.logout();
		session.removeAttribute("user");
		return "login";
	} 
}

	@RequestMapping("/add")
	public String add() {
		return "add";
	}
	
	@RequestMapping("/update")
	public String update() {
		return "update";
	}
	@RequestMapping("/index")
	public String index() {
		return "index";
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值