• shiro入门


    ------------恢复内容开始------------

    1. 概述

    1. 简介

    Apache Shiro是一个强大且易用的Java安全框架

    可以完成身份验证、授权、密码和会话管理

    Shiro 不仅可以用在 JavaSE 环境中,也可以用在 JavaEE 环境中

    官网: http://shiro.apache.org/

    2. 功能

    Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

    Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

    Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

    Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

    Web Support:Web支持,可以非常容易的集成到Web环境;

    Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

    Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

    Testing:提供测试支持;

    Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

    Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

    3. 从外部看

    应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject;其每个API的含义:

    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能得到合法的用户及其权限进行判断。

    从以上也可以看出,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入

    4. 外部架构

    Subject:主体,可以看到主体可以是任何可以与应用交互的“用户”;

    SecurityManager:相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。

    Authenticator:认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;

    Authrizer:授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

    Realm:可以有1个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;由用户提供;注意:Shiro不知道你的用户/权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的Realm;

    SessionManager:如果写过Servlet就应该知道Session的概念,Session呢需要有人去管理它的生命周期,这个组件就是SessionManager;而Shiro并不仅仅可以用在Web环境,也可以用在如普通的JavaSE环境、EJB等环境;所有呢,Shiro就抽象了一个自己的Session来管理主体与应用之间交互的数据;这样的话,比如我们在Web环境用,刚开始是一台Web服务器;接着又上了台EJB服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到Memcached服务器);

    SessionDAO:DAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;另外SessionDAO中可以使用Cache进行缓存,以提高性能;

    CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

    Cryptography:密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的
    ————————————————

    5. 认证流程

    在这里插入图片描述
    用户 提交 身份信息、凭证信息 封装成 令牌 交由 安全管理器 认证

    2. 快速入门
    1. 拷贝案例
    按照官网提示找到 快速入门案例

    GitHub地址:shiro/samples/quickstart/

    从GitHub 的文件中可以看出这个快速入门案例是一个 Maven 项目

    新建一个 Maven 工程,删除其 src 目录,将其作为父工程

    在父工程中新建一个 Maven 模块


    复制快速入门案例 POM.xml 文件中的依赖 (版本号自选)

    <dependencies>
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.1</version>
    </dependency>

    <!-- configure logging -->
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.29</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.29</version>
    </dependency>
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
    </dependencies>

    把快速入门案例中的 resource 下的log4j.properties 复制下来

    复制一下 shiro.ini 文件

    复制一下 Quickstart.java 文件
    如果有导包的错误,把那两个错误的包删掉,就会自动导对的包了,快速入门案例中用的方法过时了

    运行 Quickstart.java,得到结果


    2. 分析案例
    通过 SecurityUtils 获取当前执行的用户 Subject

    Subject currentUser = SecurityUtils.getSubject();
    1
    通过 当前用户拿到 Session

    Session session = currentUser.getSession();
    1
    用 Session 存值取值

    session.setAttribute("someKey", "aValue");
    String value = (String) session.getAttribute("someKey");
    1
    2
    判断用户是否被认证

    currentUser.isAuthenticated()
    1
    执行登录操作

    currentUser.login(token);
    1
    打印其标识主体

    currentUser.getPrincipal()
    1
    注销

    currentUser.logout();
    1
    总览

    3. SpringBoot 集成 Shiro
    1. 编写配置文件
    在刚刚的父项目中新建一个 springboot 模块

    导入 SpringBoot 和 Shiro 整合包的依赖

    <!--SpringBoot 和 Shiro 整合包-->
    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring-boot-web-starter -->
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.6.0</version>
    </dependency>

    下面是编写配置文件
    Shiro 三大要素

    subject -> ShiroFilterFactoryBean
    securityManager -> DefaultWebSecurityManager
    realm
    实际操作中对象创建的顺序 : realm -> securityManager -> subject

    编写自定义的 realm ,需要继承 AuthorizingRealm

    编写自定义的 realm ,需要继承 AuthorizingRealm

    //自定义的 Realm
    public class UserRealm extends AuthorizingRealm {
    //授权

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    //打印一个提示
    System.out.println("执行了授权方法");
    return null;
    }

    //认证

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    //打印一个提示
    System.out.println("执行了认证方法");
    return null;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    新建一个 ShiroConfig配置文件
    1、按照上面说的创建过程来写
    创建 Realm

    //3. realm
    //让 spring 托管自定义的 realm 类
    @Bean
    public UserRealm userRealm(){
    return new UserRealm();
    }
    1
    2
    3
    4
    5
    6
    2、创建 securityManager

    需要传入一个 Realm

    //2. securityManager -> DefaultWebSecurityManager
    // @Qualifier("userRealm") 指定 Bean 的名字为 userRealm
    // spring 默认的 BeanName 就是方法名
    // name 属性 指定 BeanName
    @Bean(name = "SecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurity(@Qualifier("userRealm") UserRealm userRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //需要关联自定义的 Realm,通过参数把 Realm 对象传递过来
    securityManager.setRealm(userRealm);
    return securityManager;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    3、创建 subject

    需要传入一个 securityManager

    //1. subject -> ShiroFilterFactoryBean
    // @Qualifier("securityManager") 指定 Bean 的名字为 securityManager

    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager securityManager){
    ShiroFilterFactoryBean subject = new ShiroFilterFactoryBean();
    //设置安全管理器
    //需要关联 securityManager ,通过参数把 securityManager 对象传递过来
    subject.setSecurityManager(securityManager);
    return subject;
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    2. 搭建简单测试环境

    2. 搭建简单测试环境

      1. 新建一个登录页面
      2. 新建一个首页
        首页上有三个链接,一个登录,一个增加用户,一个删除用户
      3. 新建一个增加用户页面
      4. 新建一个删除用户页面
      5. 编写对应的 Controller

    ------------恢复内容结束------------

    新建测试页面:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http:www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1>首页</h1>
    <p th:text="${msg}"></p>
    </body>
    </html>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    新建controller

    @Controller
    public class MyController {

    @GetMapping({"/","/index"})
    public String toIndex(Model model){
    model.addAttribute("msg", "hello shiro");
    return "index";
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    测试成功。

    2、整合springboot
    1、引入依赖

    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.7.1</version>
    </dependency>
    1
    2
    3
    4
    5
    2、编写自定义Realm

    //自定义的UserRealm
    public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了=>授权doGetAuthorizationInfo");
    return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("执行了=>认证doGetAuthorizationInfo");
    return null;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    3、编写ShiroConfig

    @Configuration
    public class ShiroConfig {

    //ShiroFilterFactoryBean:3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
    ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
    bean.setSecurityManager(defaultWebSecurityManager);
    return bean;
    }

    //DefaultWebSecurityManager:2
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
    }


    //创建realm对象, 需要自定义
    @Bean
    public UserRealm userRealm(){
    return new UserRealm();
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    4、创建测试页面:

    4、实现登录拦截拦截
    ShiroConfig.java

    @Configuration
    public class ShiroConfig {

    //ShiroFilterFactoryBean:3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
    ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
    //设置安全管理器
    bean.setSecurityManager(defaultWebSecurityManager);

    //添加Shiro的内置过滤器
    /*anon: 无需认证就可以访问
    * authc: 必须认证了才能访问
    * user:必须拥有 记住我 功能才能访问
    * perms:拥有对某个资源的权限才能访问
    * role:拥有某个角色权限才能访问
    * */
    LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();

    //filterMap.put("/user/add", "authc");
    //filterMap.put("/user/update", "authc");
    filterMap.put("/user/**", "authc");

    bean.setFilterChainDefinitionMap(filterMap);

    //设置登录的请求
    bean.setLoginUrl("/tologin");

    return bean;
    }

    //DefaultWebSecurityManager:2
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
    }


    //创建realm对象, 需要自定义
    @Bean
    public UserRealm userRealm(){
    return new UserRealm();
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    5、实现用户认证
    MyController.java

    ....
    @RequestMapping("/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model){
    //获取当前用户
    Subject subject = SecurityUtils.getSubject();
    //封装用户数据
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);

    try {
    subject.login(token);
    return "index";
    } catch (UnknownAccountException e){ //用户名不存在
    model.addAttribute("msg", "用户名不存在");
    return "login";
    } catch (IncorrectCredentialsException e){ //密码不存在
    model.addAttribute("msg", "密码错误");
    return "login";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http:www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1>登录</h1>
    <p th:text="${msg}" style="color: red"></p>
    <form th:action="@{/login}">
    <p> 用户名: <input type="text" name="username"></p>
    <p> 密码: <input type="text" name="password"></p>
    <p> <input type="submit">登录</p>
    </form>
    </body>
    </html>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Realm.java

    public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了=>授权doGetAuthorizationInfo");
    return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    System.out.println("执行了=>认证doGetAuthorizationInfo");

    //用户名、密码、数据库中取
    String name = "root";
    String password = "123456";

    UsernamePasswordToken userToken = (UsernamePasswordToken) token;

    if (!userToken.getUsername().equals(name)){
    return null; // 抛出异常 UnknownAccountException
    }

    //密码认证,shiro做
    return new SimpleAuthenticationInfo("", password, "");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    6、整合mybatisplus
    1、引入依赖

    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
    </dependency>
    <!-- 模板引擎 -->
    <dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
    </dependency>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    2、数据库


    3、配置数据源

    spring:
    datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/shiro_study
    driver-class-name: com.mysql.jdbc.Driver
    1
    2
    3
    4
    5
    6
    3、代码生成器

    // 代码自动生成器
    public class xmhCode {
    public static void main(String[] args) {
    // 需要构建一个 代码自动生成器 对象
    AutoGenerator mpg = new AutoGenerator();
    // 配置策略
    // 1、全局配置
    GlobalConfig gc = new GlobalConfig();
    String projectPath = System.getProperty("user.dir");
    gc.setOutputDir(projectPath+"/02_shiro_springboot/src/main/java");
    gc.setOpen(false);
    gc.setFileOverride(false); // 是否覆盖
    gc.setServiceName("%sService"); // 去Service的I前缀
    gc.setIdType(IdType.ID_WORKER);
    gc.setDateType(DateType.ONLY_DATE);
    gc.setSwagger2(true);
    mpg.setGlobalConfig(gc);
    //2、设置数据源
    DataSourceConfig dsc = new DataSourceConfig();
    dsc.setUrl("jdbc:mysql://localhost:3306/shiro_study");
    dsc.setDriverName("com.mysql.jdbc.Driver");
    dsc.setUsername("root");
    dsc.setPassword("123456");
    dsc.setDbType(DbType.MYSQL);
    mpg.setDataSource(dsc);
    //3、包的配置
    PackageConfig pc = new PackageConfig();
    pc.setParent("com.xmh");
    pc.setEntity("pojo");
    pc.setMapper("mapper");
    pc.setService("service");
    pc.setController("controller");
    mpg.setPackageInfo(pc);
    //4、策略配置
    StrategyConfig strategy = new StrategyConfig();

    strategy.setInclude("user"); // 设置要映射的表名
    strategy.setNaming(NamingStrategy.underline_to_camel);
    strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    strategy.setEntityLombokModel(true); // 自动lombok;
    strategy.setLogicDeleteFieldName("deleted");
    //自动填充配置
    TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
    TableFill gmtModified = new TableFill("gmt_modified",
    FieldFill.INSERT_UPDATE);
    ArrayList<TableFill> tableFills = new ArrayList<>();
    tableFills.add(gmtCreate);
    tableFills.add(gmtModified);
    strategy.setTableFillList(tableFills);
    //乐观锁
    strategy.setVersionFieldName("version");
    strategy.setRestControllerStyle(true);
    strategy.setControllerMappingHyphenStyle(true);
    mpg.setStrategy(strategy);
    mpg.execute(); //执行
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    4、运行代码生成器。并且在springboot启动类上标注mapperScan()


    5、测试

    @SpringBootTest
    class ApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void contextLoads() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("username", "xmh");
    User one = userService.getOne(wrapper);
    System.out.println(one);

    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    6、从数据库中查询用户名密码:
    UserRealm.java

    //自定义的UserRealm
    public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了=>授权doGetAuthorizationInfo");
    return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    System.out.println("执行了=>认证doGetAuthorizationInfo");

    UsernamePasswordToken userToken = (UsernamePasswordToken) token;

    //用户名、密码、数据库中取
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("username", userToken.getUsername());
    User user = userService.getOne(wrapper);

    if (user == null){
    return null;// 抛出异常 UnknownAccountException
    }
    //密码认证,shiro做
    return new SimpleAuthenticationInfo("", user.getPassword(), "");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    7、启动测试,测试成功!

    7、实现请求授权
    controller中新增未授权页面

    ...
    @RequestMapping("/noauth")
    @ResponseBody
    public String noauth(){
    return "未经授权,无法访问此页面";
    }

    1
    2
    3
    4
    5
    6
    7
    ShiroConfig.java

    @Configuration
    public class ShiroConfig {

    //ShiroFilterFactoryBean:3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
    ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
    //设置安全管理器
    bean.setSecurityManager(defaultWebSecurityManager);

    //添加Shiro的内置过滤器
    /*anon: 无需认证就可以访问
    * authc: 必须认证了才能访问
    * user:必须拥有 记住我 功能才能访问
    * perms:拥有对某个资源的权限才能访问
    * role:拥有某个角色权限才能访问
    * */
    LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();

    //授权,正常情况下,没有授权会跳转到未授权页面
    filterMap.put("/user/add", "perms[user:add]");
    filterMap.put("/user/update", "perms[user:update]");


    //filterMap.put("/user/add", "authc");
    //filterMap.put("/user/update", "authc");
    filterMap.put("/user/**", "authc");

    bean.setFilterChainDefinitionMap(filterMap);

    //设置登录的请求
    bean.setLoginUrl("/toLogin");
    //未授权 跳转到未授权页面
    bean.setUnauthorizedUrl("/noauth");

    return bean;
    }

    //DefaultWebSecurityManager:2
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
    }


    //创建realm对象, 需要自定义
    @Bean
    public UserRealm userRealm(){
    return new UserRealm();
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    增加数据库权限字段:


    Realm.java

    //自定义的UserRealm
    public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了=>授权doGetAuthorizationInfo");

    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

    //拿到当前登录的这个对象
    Subject subject = SecurityUtils.getSubject();
    User currentUser = (User) subject.getPrincipal();//拿到user对象

    //设置当前用户的权限
    info.addStringPermission(currentUser.getPerms());

    return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    System.out.println("执行了=>认证doGetAuthorizationInfo");

    UsernamePasswordToken userToken = (UsernamePasswordToken) token;

    //用户名、密码、数据库中取
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("username", userToken.getUsername());
    User user = userService.getOne(wrapper);

    if (user == null){
    return null;// 抛出异常 UnknownAccountException
    }
    //密码认证,shiro做
    return new SimpleAuthenticationInfo(user, user.getPassword(), "");
    }
    }

  • 相关阅读:
    c++关键字static的作用
    react 中echarts-for-react使用 自适应div
    react Echart 自适应问题
    react 中Echarts不自适应问题
    解决 react typescript 中 antD 走马灯 this.slider 报错
    antD 走马灯跳到指定页面
    js 判断语句 或的写法
    ajax 分页点击数据缓存
    react antD moment
    react antD 日期选择
  • 原文地址:https://www.cnblogs.com/lyy0622/p/15037535.html
Copyright © 2020-2023  润新知