Shiro認證和受權

shiro是一款權限控制的後臺框架,能夠控制用戶-角色-權限的分配,例如資源和路徑等等。html

主要內容:java

ShiroFilterFactoryBean工廠類mysql

SecurityManager安全管理器web

MyRealm extends AuthorizingRealm自定義Realm,實現doGetAuthenticationInfo(認證)和doGetAuthorizationInfo(受權)方法。spring

還有其餘一些rememberMe、Session和Cache功能。sql

下面使用SpringBoot整合Shiro的例子簡單說明apache

表:數據中用戶密碼要存儲加密後的密文安全

pom.xml文件cookie

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>online.myson</groupId>
	<artifactId>shiro</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>Shiro</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- shiro -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
		<!-- Spring Data JPA -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-jpa</artifactId>
		    <version>2.0.1.RELEASE</version>
		</dependency>
		<!-- mysql -->
		<dependency>
		    <groupId>mysql</groupId>
		    <artifactId>mysql-connector-java</artifactId>
		    <version>5.1.45</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

shiro配置類app

package online.myson.config;

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

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import online.myson.shiro.MyRealm;

@Configuration
public class ShiroConfig {

	/**
	 * 註冊ShiroFilterFactoryBean,實際上是註冊一個filter
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
		
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 設置securityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		
		// 設置攔截器
		Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
		// 過濾鏈定義,從上向下執行,通常將/**放最下面
		// authc:全部的url都必須認證經過才能夠訪問;anon:全部url均可以匿名訪問
		filterChainDefinitionMap.put("/statics/**", "anon");
		filterChainDefinitionMap.put("/login.html", "anon");
		filterChainDefinitionMap.put("/login", "anon");
		filterChainDefinitionMap.put("/user/**", "user");
		filterChainDefinitionMap.put("/*", "authc");
		// 不設置自動尋找根目錄下的/login.jsp頁面
		shiroFilterFactoryBean.setLoginUrl("/index");
		
		// 登陸成功後要跳轉的鏈接
		shiroFilterFactoryBean.setSuccessUrl("/index");
		
		// 未受權頁面
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;	
	}
	
	/**
	 * 註冊securityManager
	 */
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(myRealm());
		securityManager.setRememberMeManager(cookieRememberMeManager());
		return securityManager;
	}
	
	/**
	 * 註冊自定義Realm
	 */
	@Bean
	public MyRealm myRealm() {
		MyRealm myRealm = new MyRealm();
		myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
		return myRealm;
	}
	
	/**
	 * 註冊HashedCredentialsMatcher,加解密
	 */
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		
		hashedCredentialsMatcher.setHashAlgorithmName("md5");
		hashedCredentialsMatcher.setHashIterations(2);
		
		return hashedCredentialsMatcher;
		
	}
	
	/**
	 * 註冊CookieRememberMeManager
	 */
	@Bean
	public CookieRememberMeManager cookieRememberMeManager() {
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCookie(simpleCookie());
		return cookieRememberMeManager;
	}
	
	/**
	 * 註冊SimpleCookie
	 */
	@Bean
	public SimpleCookie simpleCookie() {
		SimpleCookie simpleCookie = new SimpleCookie();
		simpleCookie.setPath("/");
		simpleCookie.setHttpOnly(true);
		simpleCookie.setMaxAge(604800);// 時間
		return simpleCookie;
	}
	
	/**
	 * 開啓shiro aop支持
	 * 用於受權
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor AuthorizationAttributeSourceAdvisor(
			SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
						= new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
	
	public static void main(String[] args) {
		Object obj = new SimpleHash("md5","123456",ByteSource.Util.bytes("user"),2);
		System.out.println(obj);
	}
}

 

一、認證

// 認證
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 獲取用戶輸入的帳號
		String username = (String)token.getPrincipal();
		System.out.println(token.getCredentials());
		
		// 查詢是否存在帳號
		SysUser user = sysUserService.findByUsername(username);
		System.out.println(user);
		if(user == null) {
			return null;
		}
		
		// 驗證密碼
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
					user,
					user.getPassword(),
					ByteSource.Util.bytes(user.getSalt()),// salt
					"MyRealm"// realmName
				);
		
		return authenticationInfo;
	}

Controller類:

@PostMapping("/login")
	public ModelAndView login(SysUser user) {
		ModelAndView mv = new ModelAndView("/login");
		String msg = "成功";
		
		Subject subject = SecurityUtils.getSubject();
		
		UsernamePasswordToken token = 
				new UsernamePasswordToken(user.getUsername(), user.getPassword());
		
		try {
			subject.login(token);
		}catch(Exception e) {
			if(e instanceof UnknownAccountException) {
				msg = "帳戶不存在";
			}else if(e instanceof IncorrectCredentialsException) {
				msg = "密碼不正確";
			}else {
				msg = e.getMessage();
			}
		}
		
		mv.addObject("msg", msg);
		return mv;
	}

二、受權

三種方式:

a、經過Subject.isPermitted("userInfo:view")和subject.hasRole("admin")的一些方法,if else來控制

b、經過註解AOP控制

c、jsp頁面使用標籤<shiro>控制

// 受權
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		SysUser user = (SysUser) principals.getPrimaryPrincipal();
		
		// 獲取用戶的角色和對應的權限,這裏一次性查角色和權限了,也能夠寫sql查
		for(SysRole role : user.getRoleList()) {
			authorizationInfo.addRole(role.getRole());
			for(SysPermission permission : role.getPermissions()) {
				authorizationInfo.addStringPermission(permission.getPermission());
			}
		}
		
		return authorizationInfo;
	}

Controller:

/**
	 * 用戶添加
	 */
	@GetMapping("/user/add")
	@RequiresPermissions("userInfo:view")
	public String userAdd() {
		Subject subject = SecurityUtils.getSubject();
//		if(subject.isPermitted("userInfo:view")) {
//			return "userAdd";
//		}else {
//			return "no authc";
//		}
		return "userAdd";
相關文章
相關標籤/搜索