1. 程式人生 > >Springboot2(23)輕鬆整合shiro(帶驗證碼)

Springboot2(23)輕鬆整合shiro(帶驗證碼)

原始碼地址

springboot2教程系列

Shiro配置

1.Spring整合Shiro一般通過xml配置,SpringBoot整合Shiro一般通過java程式碼配合@Configuration和@Bean配置。

2.Shiro的核心通過過濾器Filter實現。Shiro中的Filter是通過URL規則來進行過濾和許可權校驗,所以我們需要定義一系列關於URL的規則和訪問許可權。

3.SpringBoot整合Shiro,我們需要寫的主要是兩個類,ShiroConfiguration類,還有繼承了AuthorizingRealm的Realm類。

  • ShiroConfiguration類,用來配置Shiro,注入各種Bean。包括過濾器(shiroFilter)、安全事務管理器(SecurityManager)、密碼憑證(CredentialsMatcher)、aop註解支援(authorizationAttributeSourceAdvisor)等等
  • Realm類,包括登陸認證(doGetAuthenticationInfo)、授權認證(doGetAuthorizationInfo)

引入依賴

   <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
		<shiro.version>1.4.0</shiro.version>
		<commons.lang.version>2.6</commons.lang.version>
		<kaptcha.version>0.0.9</kaptcha.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-spring</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>${commons.lang.version}</version>
		</dependency>

		<dependency>
			<groupId>com.github.axet</groupId>
			<artifactId>kaptcha</artifactId>
			<version>${kaptcha.version}</version>
		</dependency>
		
    </dependencies>

編寫ShiroConfiguration類

/**
 * Shiro的配置檔案
 */
@Configuration
public class ShiroConfig {

    /**
     * Session會話管理器,session交給shiro管理
     */
    @Bean
    public DefaultWebSessionManager sessionManager(@Value("${myframe.sessionTimeout:3600}") long globalSessionTimeout){
        DefaultWebSessionManager sessionManager =
new DefaultWebSessionManager(); //是否開啟會話驗證器,預設是開啟的 sessionManager.setSessionValidationSchedulerEnabled(true); //禁止URL地標後面新增JSESSIONID sessionManager.setSessionIdUrlRewritingEnabled(false); //設定全域性會話超時時間 sessionManager.setGlobalSessionTimeout(globalSessionTimeout * 1000); sessionManager.setSessionValidationInterval(globalSessionTimeout * 1000); return sessionManager; } /** * 安全管理器 * @param userRealm * @param sessionManager * @return */ @Bean("securityManager") public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); securityManager.setRememberMeManager(null); securityManager.setSessionManager(sessionManager); return securityManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setLoginUrl("/login.html"); shiroFilter.setUnauthorizedUrl("/"); Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/public/**", "anon"); filterMap.put("/login.html", "anon"); filterMap.put("/sys/login", "anon"); filterMap.put("/captcha.jpg", "anon"); filterMap.put("/**", "authc"); shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter; } /** * Shiro生命週期處理器,保證實現了Shiro內部lifecycle函式的bean執行 * @return */ @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 啟用shrio授權註解攔截方式,AOP式方法級許可權檢查 * @return */ @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); proxyCreator.setProxyTargetClass(true); return proxyCreator; } /** * 加入註解的使用,不加入這個註解不生效 使用shiro框架提供的切面類,用於建立代理物件 * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }

過濾器Filter實現

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean shiroFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //該值預設為false,表示生命週期由SpringApplicationContext管理,設定為true則表示由ServletContainer管理
        registration.addInitParameter("targetFilterLifecycle", "true");
        registration.setOrder(Integer.MAX_VALUE - 1);
        registration.setEnabled(true);
        registration.addUrlPatterns("/*");
        return registration;
    }

}

Realm類實現

/**
 * 認證
 */
@Component
public class UserRealm extends AuthorizingRealm {
    @Resource
    private SysUserDao sysUserDao;
    
    /**
     * 授權(驗證許可權時呼叫)
     */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
		Long userId = user.getUserId();
        //使用者許可權列表
		Set<String> permsSet = new HashSet<>();
		String perms = sysUserDao.queryAllPerms(userId);
		permsSet.addAll(Arrays.asList(perms.trim().split(",")));
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setStringPermissions(permsSet);
		return info;
	}

	/**
	 * 認證(登入時呼叫)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken)authcToken;
		//查詢使用者資訊
		SysUserEntity user = sysUserDao.selectOne(token.getUsername());
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
		return info;
	}

}

登入實現類

**
 * 登入相關
 */
@Controller
public class SysLoginController {
	@Autowired
	private Producer producer;

	/**
	 * 生成驗證碼
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping("captcha.jpg")
	public void captcha(HttpServletResponse response)throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //生成文字驗證碼
        String text = producer.createText();
        //生成圖片驗證碼
        BufferedImage image = producer.createImage(text);
        //儲存到shiro session
        ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);
        
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
	}
	
	/**
	 * 登入
	 */
	@ResponseBody
	@RequestMapping(value = "/sys/login", method = RequestMethod.POST)
	public R login(String username, String password, String captcha) throws IllegalAccessException {
		String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
		if(!captcha.equalsIgnoreCase(kaptcha)){
			return R.error("驗證碼不正確");
		}
		try{
			Subject subject = ShiroUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);
			subject.login(token);
		}catch (UnknownAccountException e) {
			return R.error(e.getMessage());
		}catch (LockedAccountException e) {
			return R.error("賬號已被鎖定,請聯絡管理員");
		} catch (IncorrectCredentialsException e) {
			return R.error("賬號或密碼不正確");
		}catch (AuthenticationException e) {
			return R.error("賬戶驗證失敗");
		}
		return R.ok();
	}
	
	/**
	 * 退出
	 */
	@RequestMapping(value = "logout", method = RequestMethod.GET)
	public String logout() {
		ShiroUtils.logout();
		return "redirect:login.html";
	}
	
}

許可權測試類

@RestController
public class PermController {

    @RequestMapping("/sysRead")
    @RequiresPermissions("sys:read")
    public String sysRead(){
        return "you can sysRead";
    }

    @RequiresPermissions("sys:write")
    @RequestMapping("/sysWrite")
    public String sysWrite(){
        return "you can sysWrite";
    }

    @RequiresPermissions("sys:delete")
    @RequestMapping("/sysDelete")
    public String sysDel(){
        return "you can sysDelete";
    }
}

每次訪問帶有@RequiresPermissions()方法時,都會進入UserRealm類的AuthorizationInfo()授權方法

另外subject.hasRole(“admin”) 或 subject.isPermitted(“admin”) 也會呼叫AuthorizationInfo()授權方法

登入測試(使用者密碼tom/123456)
在這裡插入圖片描述

許可權測試
在這裡插入圖片描述