权限框架——shiro的使用看这篇就够了

关于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
  1. realm作用:Shiro 从 Realm 获取安全数据
    默认自带的realm:idae查看realm继承关系,有默认实现和自定义继承的realm 两个概念
  2. 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才能通过

这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。

  1. anon,authcBasic,auchc,user是第一组,
  2. 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
sessionid过期时间设置
4.3、前端传的凭证名称是由后端sessionmanager规定
凭证设置

发布了47 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42083036/article/details/105701439