SpringBoot整合Shiro

SpringBoot整合Shiro安全框架。

导入Jar包


    org.apache.shiro
    shiro-core
    1.4.0



    org.apache.shiro
    shiro-spring
    1.4.0

配置自定义Realm

package com.plf.springbootexample.realm;

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

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.authc.UsernamePasswordToken;
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.apache.shiro.util.ByteSource;

public class MyShiroRealm extends AuthorizingRealm{

	
	/**
	 * 认证、登录
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
				 throws AuthenticationException {
		//1、把AuthenticationToken强转成UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		
		//2、从UsernamePasswordToken中获取username
		String username = upToken.getUsername();
		
		//3、调用数据库方法,从数据库中查询username对应的用户记录
		System.out.println("从数据库中获取用户:"+username);
		
		//4、根据用户情况,来构建AuthenticationInfo对象并返回
		//以下信息是从数据库中获取的
		//1) principal 认证的实体信息  可以是username 也可以是数据表对应的用户的实体类对象
		Object principal = username;
			
		//2) credentials 密码 明文123456
		Object credentials="fc1709d0a95a6be30bc5926fdb7f22f4";
		
		//3) realmName 当前realm对象的name 调用父类的getName()方法即可
		String realmName = getName();
		
		//4)盐值
		ByteSource credentialsSalt =null;
		
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,
				credentials,credentialsSalt,realmName);
		
		return info;
	}


	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		//从PrincipalCollection中获取登录用户的信息
		Object principal = principals.getPrimaryPrincipal();
		
		//利用登录的用户信息来确定当前用户的角色和权限
		//从数据库中获取到用户的权限
		Set roles = new HashSet<>();
		roles.add("user");
		
		if("admin".equals(principal)){
			roles.add("admin");
		}
		
		//创建SimpleAuthorizationInfo 并设置其roles属性
		SimpleAuthorizationInfo info =new SimpleAuthorizationInfo(roles);
		
		//返回SimpleAuthorizationInfo对象 
		return info;
	}
}

配置Shiro

package com.plf.springbootexample.config;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;

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

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;  
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
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 com.plf.springbootexample.realm.MyShiroRealm;

@Configuration
public class ShiroConfig {

	/**
	* 负责shiroBean的生命周期
	* @return
	*/
	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
		return new LifecycleBeanPostProcessor();
	}

	/**
	* 自定义的认证类,用于用户的认证、登录、授权
	* @return
	*/
	@Bean
	public MyShiroRealm myShiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher){
		MyShiroRealm myShiroRealm = new MyShiroRealm();
		myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
		return myShiroRealm;
	}

	@Bean
	public SecurityManager  securityManager(MyShiroRealm myShiroRealm) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(myShiroRealm);
		return securityManager;
	}

	/**
	* 配置Shiro的MD5加密
	*/
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		//指定加密方式为MD5
		credentialsMatcher.setHashAlgorithmName("MD5");
		//加密次数
		credentialsMatcher.setHashIterations(1024);
		//credentialsMatcher.setStoredCredentialsHexEncoded(true);
		return credentialsMatcher;
	}

	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		//拦截器
		Map filterChainDefinitionMap = new LinkedHashMap();
		//anon 所有url都可以匿名访问
		//authc 所有url都必须认证通过才可以访问
		//user 配置记住我活着认证通过才可以访问
		//logout 退出登录
		
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/static/**", "anon");
		//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
		filterChainDefinitionMap.put("/logout", "logout");
		
		filterChainDefinitionMap.put("/shiro/index", "anon");
		
		filterChainDefinitionMap.put("/shiro/login", "anon");
		
		filterChainDefinitionMap.put("/shiro/user", "authc,roles[user]");
		
		filterChainDefinitionMap.put("/shiro/admin", "authc,roles[admin]");
		
		
		// 过滤连接自定义,从上往下顺序执行,所以使用LinkHashMap /**放在最下面
		filterChainDefinitionMap.put("/**", "authc");
		
		
		shiroFilterFactoryBean.setLoginUrl("/shiro/index");
		// 登录成功后要跳转的链接
		shiroFilterFactoryBean.setSuccessUrl("/shiro/success");
		//未授权界面;
		shiroFilterFactoryBean.setUnauthorizedUrl("/shiro/fail");
		
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}


	//启用Shiro的注解 
	@Bean
	@ConditionalOnMissingBean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAAP 
				= new DefaultAdvisorAutoProxyCreator();
		defaultAAP.setProxyTargetClass(true);
		return defaultAAP;
	}
		
	@Bean
	public AuthorizationAttributeSourceAdvisor 
			authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
					= new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
}

配置异常跳转

因为考虑到Shiro出现无权限等情况会报异常,这样对整个项目不友好,就是自己定义全局异常处理。

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalDefaultExceptionHandler {
	
	@ExceptionHandler(Exception.class)
	public String defaultExceptionHandler(HttpServletRequest req,Exception e){
		if(e instanceof UnauthorizedException){
			return "noperssion";
		}
		return "defaultException";
	}
}

Shiro注解

import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Repository;

@Repository
public class LoginService {

	//admin权限才能访问
	@RequiresRoles("admin") 
	public void ShiroService(){
		System.out.println("======ShiroService======");
	}
}

控制器测试

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.plf.springbootexample.service.LoginService;

@Controller
@RequestMapping("shiro")
public class LoginController {
	
	
	@Autowired
	private LoginService loginService;


	@RequestMapping("testService")
	public String testService(){
		
		loginService.ShiroService();
		
		return "success";
	}


	@RequestMapping("login")
	public String Login(@RequestParam String username
			,@RequestParam String password){
		Subject currentUser = SecurityUtils.getSubject();
		
		if(!currentUser.isAuthenticated()){
			//把用户名和密码封装为UsernamePasswordToken对象
			UsernamePasswordToken token = new UsernamePasswordToken(username,password);
			token.setRememberMe(true);
			try{
				currentUser.login(token);
			}catch(AuthenticationException e){
				System.out.println("登录失败:"+e.getMessage());
				return "fail";
			}
		}
		return "success";
	}
}

你可能感兴趣的:(spring,boot,后端,java)