基于SpringBoot2的Shiro最簡(jiǎn)配置操作(兩個(gè)文件)
基礎(chǔ)環(huán)境:依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.4.0</version> </dependency>
如果不是前后端分離,要實(shí)現(xiàn)頁(yè)面級(jí)的權(quán)限控制,則加入以下依賴就可以使用shiro的權(quán)限標(biāo)簽了(記得在html頭部加上相應(yīng)約束:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="Thymeleaf" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro" lang="en"> ): <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
Realm:認(rèn)證鑒權(quán)器
package com.rz.monomer.modules.shiro;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rz.monomer.modules.user.entity.SysUserInfo;
import com.rz.monomer.modules.user.entity.SysUserRole;
import com.rz.monomer.modules.user.service.SysButtonInfoService;
import com.rz.monomer.modules.user.service.SysUserInfoService;
import com.rz.monomer.modules.user.service.SysUserRoleService;
import lombok.extern.slf4j.Slf4j;
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 java.util.Set;
import java.util.stream.Collectors;
/**
* 認(rèn)證、鑒權(quán)類(必須)
*
* @author sunziwen
* @version 1.0
* @date 2019/11/14 14:06
**/
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
//以下三個(gè)服務(wù)是普通Dao查詢,從數(shù)據(jù)庫(kù)查詢用戶及其角色權(quán)限信息(這個(gè)類沒(méi)有自動(dòng)注入,需要在下個(gè)文件中手動(dòng)注入)
private SysUserInfoService userInfoService;
private SysButtonInfoService buttonInfoService;
private SysUserRoleService userRoleService;
public ShiroRealm(SysUserInfoService userInfoService, SysButtonInfoService buttonInfoService, SysUserRoleService userRoleService) {
this.userInfoService = userInfoService;
this.buttonInfoService = buttonInfoService;
this.userRoleService = userRoleService;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
log.info("check authorization info");
SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
// 獲取當(dāng)前用戶
SysUserInfo userInfo = (SysUserInfo) principals.getPrimaryPrincipal();
// 查詢角色信息
Set<Long> userRoles = userRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userInfo.getId()))
.stream()
.map(SysUserRole::getRoleId)
.collect(Collectors.toSet());
//角色所有權(quán)限
Set<String> perms = buttonInfoService.getPermsByRoles(userRoles);
authInfo.addStringPermissions(perms);
return authInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
log.info("check authentication info");
String username = (String) token.getPrincipal();
// 獲取用戶信息
SysUserInfo user = userInfoService.getOne(new LambdaQueryWrapper<SysUserInfo>().eq(SysUserInfo::getUsername, username));
if (user == null) {
return null;
}
/*SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
ByteSource.Util.bytes(654321), getName());*/
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
return authenticationInfo;
}
}
WebSecurityManager:安全管理器
package com.rz.monomer.modules.shiro;
import com.rz.monomer.modules.user.service.SysButtonInfoService;
import com.rz.monomer.modules.user.service.SysUserInfoService;
import com.rz.monomer.modules.user.service.SysUserRoleService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Shiro配置類(必須)
*
* @author sunziwen
* @version 1.0
* @date 2019/11/14 14:08
**/
@Configuration
@Slf4j
@AllArgsConstructor
public class WebSecurityManager {
private SysUserInfoService userInfoService;
private SysButtonInfoService buttonInfoService;
private SysUserRoleService userRoleService;
/**
* 安全管理器
*/
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
return securityManager;
}
/**
* 認(rèn)證鑒權(quán)器(安全管理器的依賴)
*/
@Bean
public ShiroRealm realm() {
return new ShiroRealm(userInfoService, buttonInfoService, userRoleService);
}
/**
* 配置攔截規(guī)則
*/
@Bean
public ShiroFilterFactoryBean filter(org.apache.shiro.mgt.SecurityManager securityManager) {
log.info("config shiro filter");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 定義URL攔截鏈
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 允許匿名用戶訪問(wèn)首頁(yè)
filterChainDefinitionMap.put("/shiro/index", "anon");
// 定義注銷(xiāo)路徑
filterChainDefinitionMap.put("/shiro/logout", "logout");
// 所有用戶界面都需要身份驗(yàn)證,否則會(huì)跳轉(zhuǎn)到loginurl,由FormAuthenticationFilter處理
filterChainDefinitionMap.put("/shiro/user/**", "authc");
// 為login路徑定義攔截,由FormAuthenticationFilter處理
filterChainDefinitionMap.put("/shiro/login", "authc");
// 所有vip路徑要求具備vip角色權(quán)限
filterChainDefinitionMap.put("/shiro/vip/**", "roles[vip]");
// 指定loginurl 路徑
shiroFilterFactoryBean.setLoginUrl("/shiro/login");
// 登錄成功后跳轉(zhuǎn)路徑
shiroFilterFactoryBean.setSuccessUrl("/shiro/user/");
// for un authenticated
shiroFilterFactoryBean.setUnauthorizedUrl("/shiro/unauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
// 自定義filters,可覆蓋默認(rèn)的Filter列表,參考 DefaultFilter
Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
// 定制logout 過(guò)濾,指定注銷(xiāo)后跳轉(zhuǎn)到登錄頁(yè)(默認(rèn)為根路徑)
LogoutFilter logoutFilter = new LogoutFilter();
logoutFilter.setRedirectUrl("/shiro/login");
filters.put("logout", logoutFilter);
// 定制authc 過(guò)濾,指定登錄表單參數(shù)
FormAuthenticationFilter authFilter = new FormAuthenticationFilter();
authFilter.setUsernameParam("username");
authFilter.setPasswordParam("password");
filters.put("authc", authFilter);
shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}
}
Test:登錄測(cè)試
package com.rz.monomer.modules.user.controller;
import com.rz.monomer.commons.utils.Md5Encrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
public class LoginController {
@PostMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(username, Md5Encrypt.md5(password));
try {
// 執(zhí)行登錄
subject.login(token);
} catch (UnknownAccountException e) {
// 未知用戶
log.warn("the account {} is not found", username);
return "account not found";
} catch (IncorrectCredentialsException e) {
// 用戶或密碼不正確
log.warn("the account or password is not correct");
return "account or password not correct";
}
return "login success";
}
}
補(bǔ)充:SpringBoot配置Shiro時(shí)踩坑
在SpringBoot2.0整合shiro時(shí)使用@EnableAutoConfiguration的時(shí)候需要對(duì)config文件進(jìn)行掃描,即使用@ComponentScan對(duì)配置進(jìn)行掃描。
或者直接使用@SpringBootApplication,但是這種方法會(huì)將主方法目錄下的所有package都進(jìn)行掃描影響項(xiàng)目效率。
Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - zxc, rememberMe=false]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException
當(dāng)出現(xiàn)此異常時(shí),一般情況是用戶名密碼不匹配,或者是在配置對(duì)應(yīng)的Realm時(shí)出現(xiàn)空值導(dǎo)致匹配失敗。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
feign 如何獲取請(qǐng)求真實(shí)目的ip地址
這篇文章主要介紹了feign 獲取請(qǐng)求真實(shí)目的ip地址操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Spring JdbcTemplate實(shí)現(xiàn)添加與查詢方法詳解
JdbcTemplate是Spring框架自帶的對(duì)JDBC操作的封裝,目的是提供統(tǒng)一的模板方法使對(duì)數(shù)據(jù)庫(kù)的操作更加方便、友好,效率也不錯(cuò),這篇文章主要介紹了Spring?JdbcTemplate執(zhí)行數(shù)據(jù)庫(kù)操作,需要的朋友可以參考下2022-11-11
解決SpringBoot項(xiàng)目啟動(dòng)成功但接口訪問(wèn)404的問(wèn)題
這篇文章主要介紹了如何解決SpringBoot項(xiàng)目啟動(dòng)成功但接口訪問(wèn)404的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,接下來(lái)就跟著小編一起來(lái)看看吧2023-07-07
Spring boot整合shiro+jwt實(shí)現(xiàn)前后端分離
這篇文章主要為大家詳細(xì)介紹了Spring boot整合shiro+jwt實(shí)現(xiàn)前后端分離,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端主動(dòng)推送消息方式
這篇文章主要介紹了SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端主動(dòng)推送消息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
Spring Data Jpa 自動(dòng)生成表結(jié)構(gòu)的方法示例
這篇文章主要介紹了Spring Data Jpa 自動(dòng)生成表結(jié)構(gòu)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04

