關於shiro的學習推薦官網:
鏈接地址: http://shiro.apache.org/
前言:
Shiro 是 Java 的一個安全框架。目前,使用 Apache Shiro 的人越來越多,因爲它相當簡單,對比 SpringSecurity,可能沒有 Spring Security 做的功能強大,但是在實際工作時我們可能並不需要那麼複雜的東西,所以使用小而簡單的Shiro 就足夠了。
一、ACL和RBAC
- ACL: Access Control List
訪問控制列表 以前盛行的一種權限設計,它的核心在於用戶直接和權限掛鉤
優點:簡單易用,開發便捷 缺點:用戶和權限直接掛鉤,導致在授予時的複雜性,比較分散,不便於管理 例子:常見的文件系統權限設計, 直接給用戶加權限 - RBAC: Role Based Access Control
基於角色的訪問控制系統。權限與角色相關聯,用戶通過成爲適當角色的成員而得到這些角色的權限
優點:簡化了用戶與權限的管理,通過對用戶進行分類,使得角色與權限關聯起來 缺點:開發對比ACL相對複雜
例子:基於RBAC模型的權限驗證框架與應用 Apache Shiro、spring Security BAT企業
ACL,一般是對報表系統,阿里的ODPS
二、shiro中的一些基礎概念和專業名詞(重要)
1、基礎概念:
什麼是身份認證?
Authentication,身份證認證,一般就是登錄
什麼是授權?
Authorization,給用戶分配角色或者訪問某些資源的權限
什麼是會話管理?
Session Management, 用戶的會話管理員,多數情況下是web session
什麼是加密?
Cryptography, 數據加解密,比如密碼加解密等
什麼是主體(subject)?
主體,可以看到主體可以是任何可以與應用交互的“用戶”;
2、shiro實現原理流程圖解:
在這個流程裏面,我們可以看到API 核心就是 Subject,其中各個部分的解釋與作用——
- Subject:主體,代表了當前 “用戶”,這個用戶不一定是一個具體的人,與當前應用交互的任何東西都是Subject,如網絡爬蟲,機器人等;即一個抽象概念;所有Subject 都綁定到SecurityManager,與 Subject 的所有交互都會委託給 SecurityManager;可以把Subject 認爲是一個門面;SecurityManager纔是實際的執行者;
- SecurityManager:安全管理器;即所有與安全有關的操作都會與 SecurityManager 交互;且它管理着所有Subject;可以看出它是 Shiro 的核心,它負責與後邊介紹的其他組件進行交互,如果學習過SpringMVC,你可以把它看成DispatcherServlet 前端控制器;
- Realm:域,Shiro 從 Realm 獲取安全數據(如用戶、角色、權限),就是說 SecurityManager
要驗證用戶身份,那麼它需要從 Realm 獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從 Realm 得到用戶相應的角色 /權限進行驗證用戶是否能進行操作;可以把 Realm 看成 DataSource,即安全數據源。
如果我們寫一個最簡單的Shiro應用,那麼大概流程應該是——
應用代碼通過 Subject 來進行認證和授權,而 Subject 又委託給 SecurityManager;我們需要給 Shiro 的 SecurityManager 注入 Realm,從而讓 SecurityManager 能得到合法的用戶及其權限進行判斷。
3、架構圖;
4、框架專業名詞解讀
Subject
我們把用戶或者程序稱爲主體(如用戶,第三方服務,cron作業),主體去訪問系統或者資源
SecurityManager
安全管理器,Subject的認證和授權都要在安全管理器下進行
Authenticator
認證器,主要負責Subject的認證
Cache Manager
緩存管理器,比如認證或授權信息,通過緩存進行管理,提高性能
Session Manager
會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通 JavaSE 環境的,也可以是如 Web 環境的;
Realm
數據域,Shiro和安全數據的連接器,好比jdbc連接數據庫; 通過realm獲取認證授權相關信息
Authorizer
授權器,主要負責Subject的授權, 控制subject擁有的角色或者權限
Cryptography
加解密,Shiro的包含易於使用和理解的數據加解密方法,簡化了很多複雜的api
Concurrency
shiro 支持多線程應用的併發驗證,即如在一個線程中開啓另一個線程,能把權限自動傳播過去;
SessionDAO
DAO 大家都用過,數據訪問對象,用於會話的 CRUD,比如我們想把 Session 保存到數據庫,那麼可以實現自己的 SessionDAO,通過如 JDBC 寫到數據庫;比如想把 Session 放到 Memcached 中,可以實現自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 進行緩存,以提高性能;
5、安全數據源realm
5.1、shiro自帶的默認的realm
- realm作用:Shiro 從 Realm 獲取安全數據
默認自帶的realm:idae查看realm繼承關係,有默認實現和自定義繼承的realm 兩個概念 - principal : 主體的標示,可以有多個,但是需要具有唯一性,常見的有用戶名,手機號,郵箱等 credential:憑證, 一般就是密碼 所以一般我們說 principal + credential 就賬號 + 密碼 開發中,往往是自定義realm , 即集成 AuthorizingRealm
5.2、shiro數據源使用.ini配置文件
ini配置文件內容:
# 格式 name=password,role1,role2,..roleN
[users]
# user 'root' with password 'secret' and the 'admin' role,
jack = 456, user
# user 'guest' with the password 'guest' and the 'guest' role
xdcalss = 123, root
# 格式 role=permission1,permission2...permissionN 也可以用通配符
# 下面配置user的權限爲所有video:find,video:buy,如果需要配置video全部操作crud 則 user = video:*
[roles]
user = video:find,video:buy
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
快速啓動測試
@Test
public void test(){
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//設置token 模擬用戶輸入賬號密碼
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","456");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
subject.hasRole("admin");
System.out.println(subject.getPrincipal());
}
5.3、shiro數據源realm使用jdbc方式注入
a、使用jdbc.ini文件
#注意 文件格式必須爲ini,編碼爲ANSI
#聲明Realm,指定realm類型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#配置數據源
#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource=com.alibaba.druid.pool.DruidDataSource
# mysql-connector-java 5 用的驅動url是com.mysql.jdbc.Driver,mysql-connector-java6以後用的是 com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.cj.jdbc.Driver
#避免安全警告
dataSource.url=jdbc:mysql://localhost:3306/myshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
dataSource.username=wyy
dataSource.password=xxx
#指定數據源
jdbcRealm.dataSource=$dataSource
#開啓查找權限, 默認是false,不會去查找角色對應的權限,坑!!!!!
jdbcRealm.permissionsLookupEnabled=true
#指定SecurityManager的Realms實現,設置realms,可以有多個,用逗號隔開
securityManager.realms=$jdbcRealm
快速啓動
@Test
public void test2(){
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//設置token 模擬用戶輸入賬號密碼
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
subject.hasRole("admin");
System.out.println(subject.getPrincipal());
}
b、使用Java配置值類
@Test
public void test1(){
DefaultSecurityManager securityManager = new DefaultSecurityManager();
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/myshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
ds.setUsername("wyy");
ds.setPassword("xxx");
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setPermissionsLookupEnabled(true);
jdbcRealm.setDataSource(ds);
securityManager.setRealm(jdbcRealm);
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//設置token 模擬用戶輸入賬號密碼
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
subject.hasRole("admin");
System.out.println(subject.getPrincipal());
}
三、整合boot快速啓動
導入shiro依賴:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
這裏使用的是shiro內置的realm
/**
* @author wyy
* @version 1.0
* @date 2020/3/27 10:11
* @description
**/
public class QuickStart_shiro {
private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
private DefaultSecurityManager securityManager = new DefaultSecurityManager();
@Before
public void init(){
//添加賬戶
simpleAccountRealm.addAccount("zhangsan","123");
//設置realm 構建 環境
securityManager.setRealm(simpleAccountRealm);
}
@Test
public void test(){
//設置上下文
SecurityUtils.setSecurityManager(securityManager);
//當前操作主體
Subject subject = SecurityUtils.getSubject();
//設置token 模擬用戶輸入賬號密碼
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zhangsan","1234");
subject.login(usernamePasswordToken);
Boolean isAccess = subject.isAuthenticated();
System.out.println(isAccess);
}
}
四、shiro自定義realm(重要)
步驟:
- 創建一個AuthorizingRealm類 ,
- 繼承樹AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm
- 重寫授權方法 doGetAuthorizationInfo
- 重寫認證方法 doGetAuthenticationInfo
1、重寫方法介紹:
- 當用戶登陸的時候會調用 doGetAuthenticationInfo
- 進行權限校驗的時候會調用: doGetAuthorizationInfo
2、一些被用到的對象介紹:
UsernamePasswordToken : 對應就是 shiro的token中有Principal和Credential
繼承樹:
UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
SimpleAuthorizationInfo:代表用戶角色權限信息
SimpleAuthenticationInfo :代表該用戶的認證信息
3、自定義realm
/**
* @author wyy
* @version 1.0
* @date 2020/4/7 14:38
* @description
**/
public class CustomRealm extends AuthorizingRealm {
//創建模擬用戶
private final Map<String,String> userInfoMap = new HashMap<>();
{
userInfoMap.put("jack","123");
userInfoMap.put("admin","123");
}
//創建模擬權限
private final Map<String,Set<String>> permissionMap = new HashMap<>();
{
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add("video:find");
set1.add("video:buy");
set2.add("video:add");
permissionMap.put("jack",set1);
permissionMap.put("admin",set2);
}
//創建模擬角色
private final Map<String,Set<String>> roleMap = new HashMap<>();
{
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add("role1");
set1.add("role2");
set2.add("root");
roleMap.put("jack",set1);
roleMap.put("admin",set2);
}
//進行權限校驗的時候會調用: doGetAuthorizationInfo
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("權限:doGetAuthorizationInfo");
String name = (String)principalCollection.getPrimaryPrincipal();
Set<String> permission = getPermissionsFromDB(name);
Set<String> roles = getRolesByNameFromDB(name);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRoles(roles);
simpleAuthorizationInfo.addStringPermissions(permission);
return simpleAuthorizationInfo;
}
private Set<String> getRolesByNameFromDB(String name) {
return roleMap.get(name);
}
private Set<String> getPermissionsFromDB(String name) {
return permissionMap.get(name);
}
//當用戶登陸的時候會調用 doGetAuthenticationInfo
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("認證:doGetAuthenticationInfo");
String name = (String)authenticationToken.getPrincipal();
String pwd = getPwdByNameFromDB(name);
if(null == pwd || "".equals(pwd)){
return null;
}
//pwd 可能需要一個加鹽操作
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name,pwd,this.getName());
return simpleAuthenticationInfo;
}
private String getPwdByNameFromDB(String name) {
return userInfoMap.get(name);
}
}
4、自定義realm實例化
/**
* @author wyy
* @version 1.0
* @date 2020/4/7 14:39
* @description
**/
public class QuickStart_shiro2 {
private CustomRealm simpleAccountRealm = new CustomRealm();
private DefaultSecurityManager securityManager = new DefaultSecurityManager();
@Before
public void init(){
//設置realm 構建 環境
securityManager.setRealm(simpleAccountRealm);
//設置上下文
SecurityUtils.setSecurityManager(securityManager);
}
@Test
public void test(){
//當前操作主體
Subject subject = SecurityUtils.getSubject();
//設置token 模擬用戶輸入賬號密碼
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
subject.login(usernamePasswordToken);
Boolean isAccess = subject.isAuthenticated();
subject.checkPermission("video:find");
subject.checkPermission("video:buy");
subject.hasRole("root");
System.out.println(isAccess);
}
}
五、shiro內置過濾器Fileter講解(重要)
1、DefaultFilter 及其內部的枚舉類
ssl :org.apache.shiro.web.filter.authz.SslFilter
user :org.apache.shiro.web.filter.authz.UserFilter
anon :org.apache.shiro.web.filter.authc.AnonymousFilter
port :org.apache.shiro.web.filter.authz.PortFilter
rest :org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
authc :org.apache.shiro.web.filter.authc.FormAuthenticationFilter
perms :org.apache.shiro.web.filter.authz.PermissionAuthorizationFilter
roles :org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
logout :org.apache.shiro.web.filter.authc.LogoutFilter
authcBasic :org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
noSessionCreation :org.apache.shiro.web.filter.session.NoSessionCreationFilter
是不是感覺一頭霧水 別急下面列出對應功能
//匿名訪問 遊客訪問路徑
filterChainDefinitionMap.put("/pub/**", "anon");
//退出過濾器
filterChainDefinitionMap.put("/user/logout", "logout");
//登錄用戶才能訪問
filterChainDefinitionMap.put("/author/**", "authc");
filterChainDefinitionMap.put("/author/**", "authcBasic");
//只有admin管理員才能訪問
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//只有視頻修改權限的才能訪問
filterChainDefinitionMap.put("/goods/video/update", "perms[video_update]");
//authc : url 必須通過認證才能訪問
//anon : url可以匿名訪問
filterChainDefinitionMap.put("/**", "authc");
port:org.apache.shiro.web.filter.authz.PortFilter
端口攔截器, 可通過的端口。
ssl:org.apache.shiro.web.filter.authz.SslFilter
ssl攔截器,只有請求協議是https才能通過
這些過濾器分爲兩組,一組是認證過濾器,一組是授權過濾器。
- anon,authcBasic,auchc,user是第一組,
- perms,roles,ssl,rest,port是第二組
權限校驗的兩種方式
shiro權限控制註解和編程方式講解
1、註解方式
@RequiresRoles(value={"admin", "editor"}, logical= Logical.AND)
需要角色 admin 和 editor兩個角色 AND表示兩個同時成立
@RequiresPermissions (value={"user:add", "user:del"}, logical= Logical.OR)
需要權限 user:add 或 user:del權限其中一個,OR是或的意思。
@RequiresAuthentication
已經授過權,調用Subject.isAuthenticated()返回true
@RequiresUser
身份驗證或者通過記 住我登錄的
2、編碼形式
Subject subject = SecurityUtils.getSubject();
//基於角色判斷
if(subject.hasRole(“admin”)) {
//有角色,有權限
} else {
//無角色,無權限
}
//或者權限判斷
if(subject.isPermitted("/user/add")){
//有權限
}else{
//無權限
}
2、shiroFilterFactoryBean配置編寫(非常重要)
1、配置流程與思路
- shirofilterfactorybean -》securitymanager
- customsessionmanager
- customrealm ->HashedCredentialsmatcher
- sessionmanager
- defaultsessionmanager :默認實現常用於JavaSE
- servletcontainersessionmanager :web環境
- defaultwebsessionmanager:常用於自定義實現
2、過濾器shiroFilterFactoryBean的實現 Java配置類的書寫
/**
* @author wyy
* @version 1.0
* @Classname ShiroConfig
* @date 2020/4/16 10:56
* @description
**/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
System.out.println("ShiroFilterFactoryBean.shiroFilter() 執行了");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//這裏設置了登錄接口 如果訪問了某個接口沒有登錄 就會調用這個接口(如果不是前後端分離就返回頁面)
shiroFilterFactoryBean.setLoginUrl("/pub/need_login");
//如果是前後端分離則不需要這個
//shiroFilterFactoryBean.setSuccessUrl();
//這個是用戶登錄了 但沒有權限 就會調用這個接口
shiroFilterFactoryBean.setUnauthorizedUrl("/pub/need_permission");
/**
*攔截器路徑 坑1:部分路徑無法攔截,攔截效果時有時無,因爲使用了hashMap 是無序的應該使用linkedHashMap
*原因在於過濾鏈執行順序是順序執行所以需要使用有序的linkedHashMap
**/
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//匿名訪問 遊客訪問路徑
filterChainDefinitionMap.put("/pub/**", "anon");
//退出過濾器
filterChainDefinitionMap.put("/user/logout", "logout");
//登錄用戶才能訪問
filterChainDefinitionMap.put("/author/**", "authc");
//只有管理員才能訪問
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//視頻修改權限
filterChainDefinitionMap.put("/goods/video/update","perms[video_update]");
//坑2:過濾鏈是順序執行的,從上而下,一般來講/** 是放到最下面的
//authc : url 必須通過認證才能訪問
//anon : url可以匿名訪問
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(customRealm());
securityManager.setSessionManager(sessionManager());
return securityManager;
}
//自定義realm注入
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customRealm;
}
//自定義sessionmanager注入
@Bean
public SessionManager sessionManager() {
//使用自定義sessionmanager 具體寫法看 六—3
CustomSessionManager customSessionManager = new CustomSessionManager();
return customSessionManager;
}
//加密方式
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//設置散列算法 :這裏設置的MD5
credentialsMatcher.setHashAlgorithmName("MD5");
//設置多重加密算法 :這裏設置的是2次加密(mad5(md5(xxx)))
credentialsMatcher.setHashIterations(2);
return credentialsMatcher;
}
}
六、shiro緩存模塊
1、什麼是會話session?
用戶與程序的鏈接,程序可以根據session來區分不同的用戶。
2、什麼是會話管理器 sessionmanager?
會話管理器管理所有的subject的操作,是shiro的核心
核心方法:
//開啓一個session
Session start(SessionContext context);
//指定Key獲取session
Session getSession(SessionKey key)
shiro中的會話管理器有多個實現
SessionDao 會話存儲/持久化
SessionDAO AbstractSessionDAO CachingSessionDAO EnterpriseCacheSessionDAO MemorySessionDAO
核心方法
//創建
Serializable create(Session session);
//獲取
Session readSession(Serializable sessionId) throws UnknownSessionException;
//更新
void update(Session session)
//刪除,會話過期時會調用
void delete(Session session);
//獲取活躍的session
Collection<Session> getActiveSessions();
3、自定義sessionManager驗證
/**
* @author wyy
* @version 1.0
* @Classname CustomSessionManager
* @date 2020/4/16 13:35
* @description
**/
public class CustomSessionManager extends DefaultWebSessionManager {
private final static String AUTHORIZATION = "token";
public CustomSessionManager(){
super();
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if(null != sessionId ){
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return sessionId;
}else{
return super.getSessionId(request,response);
}
}
}
七、api驗證
/**
* @author wyy
* @version 1.0
* @Classname PublicController
* @date 2020/4/20 10:03
* @description
**/
@RestController
@RequestMapping(name = "公共接口",value = "/pub")
public class PublicController {
@RequestMapping(name = "設置的未登錄攔截接口",value = "/need_login")
public JsonData needLogin(){
return JsonData.buildSuccess(-2,"請先登錄");
}
@RequestMapping(name = "設置登錄但未授權的用戶攔截接口",value = "/need_permission")
public JsonData needPermission(){
return JsonData.buildSuccess(-3,"您沒有權限,請聯繫管理員!");
}
@RequestMapping(name = "初始化界面",value = "/index")
public JsonData index(){
List<String> goods = new ArrayList<>();
goods.add("空調");
goods.add("水壺");
goods.add("電冰箱");
goods.add("熱水器");
goods.add("烤箱");
return JsonData.buildSuccess(goods);
}
@RequestMapping(name = "登錄",value = "login")
public JsonData login(@RequestBody UserBO userBO, HttpServletRequest request, HttpServletResponse response){
Subject subject = SecurityUtils.getSubject();
Map<String,Object> map = new HashMap<>(16);
try {
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userBO.getName(), userBO.getPwd());
subject.login(usernamePasswordToken);
map.put("token",subject.getSession().getId());
}catch (Exception e){
map.put("msg","賬號或密碼不存在!");
}
return JsonData.buildSuccess(map);
}
}
1、遊客訪問接口:不需要登錄就可以訪問
@RestController
@RequestMapping(value = "author")
public class OrderController {
@RequestMapping(value = "listOrder")
public JsonData ListOrder(){
Map<String,String> map = new HashMap<>(16);
map.put("springboot基礎","19.00元");
map.put("redis基礎","29.00元");
map.put("activeMq基礎","13.00元");
return JsonData.buildSuccess(map);
}
}
2、author:需要用戶登錄才能訪問接口
@RestController
@RequestMapping(value = "/goods/video")
public class VideoController {
@RequestMapping(value = "update")
public JsonData videoUpdate(){
return JsonData.buildSuccess();
}
}
3、需要有video_update 權限的用戶才能訪問
這裏只有Jack有更新權限所以John是沒有權限訪問該接口的
/**
* @author wyy
* @version 1.0
* @date 2020/4/14 9:46
* @description
**/
@RestController
@RequestMapping(name = "用戶模塊", value = "admin")
public class UserController {
@RequestMapping(name = "根據id獲取角色所有權限",value = "/getPermissionById")
public List<Role> getRoles(@RequestParam(value = "id") Integer id){
return userService.getRoles(id);
}
}
4、注意點:
4.1、登錄時,我們輸入的是明文,但是realm使用了一層MD5加密,所以你的數據庫裏存儲的密碼應該要是密文才能校驗通過,否則就會出現下面錯誤
當然上面的登錄例子裏面進行了try catch 操作所以不會拋錯
4.2、登錄獲取的token並非永久,如果不設置過期時間shiro默認30分鐘,這裏我們在sessionmanager裏面配置了session過期時間18s
4.3、前端傳的憑證名稱是由後端sessionmanager規定