Java Apache Shiro安全框架快速开发详解流程

yizhihongxing

Java Apache Shiro安全框架快速开发详解流程

什么是Apache Shiro

Apache Shiro是一个跨应用程序、支持单点登录、支持身份验证和访问控制框架,可以解决应用程序的安全问题。
Shiro的核心是将应用程序的用户身份、安全验证、访问控制等功能组合起来实现一个完整的安全框架。
使用Shiro开发的应用程序能够快速、安全地集成身份验证、安全验证、单点登录等功能。

Shiro框架的组件

Shiro由以下组件组成:

  • Subject:应用程序中的用户抽象对象,封装了与用户相关的对象和操作。

  • SecurityManager:Shiro框架的核心,用户管理、安全认证、访问控制等功能都与SecurityManager相关。

  • Authenticator:用于验证用户身份,提供不同的验证策略,如密码验证、指纹验证等。

  • Authorizer:用于授权用户访问资源,提供多种授权策略。

  • Realm:Shiro对数据源的抽象,用于获取用户身份认证信息和访问控制数据,可以将用户信息存储在数据库、LDAP或其他数据源中。

  • SessionManager:会话管理器,负责管理用户会话,可以定制不同的会话管理策略,如Cookie会话管理、URL会话跟踪等。

Shiro集成框架

在Java开发中,Shiro常常集成在一些框架中,如Spring、Struts等,通过集成Shiro,可以轻松地实现应用程序的安全模块。

下面就以Spring集成Shiro框架为例,介绍Shiro框架的快速开发流程。

快速搭建Shiro框架

在Spring应用程序中集成Shiro框架,通常需要完成以下步骤:

  1. 添加Shiro依赖:
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.7.0</version>
</dependency>
  1. 配置Shiro相关组件:
<!-- 配置SecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm" />
</bean>

<!-- 配置Realm -->
<bean id="myRealm" class="xx.xx.xxx.MyRealm">
    <!-- 配置数据源 -->
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 配置Shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <!-- 配置过滤规则 -->
    <property name="filterChainDefinitions">
        <value>
            /login.jsp = anon
            /logout = logout
            /** = authc
        </value>
    </property>
    <!-- 配置登录URL -->
    <property name="loginUrl" value="/login.jsp" />
    <!-- 配置成功登录后的URL -->
    <property name="successUrl" value="/index.jsp" />
    <!-- 配置未登录时的URL -->
    <property name="unauthorizedUrl" value="/unauthorized.jsp" />
</bean>
  1. 编写自定义Realm:
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 获取当前用户的角色和权限信息,并添加到authorizationInfo中
        User user = (User)principals.getPrimaryPrincipal();
        Set<String> roleNames = userService.findRoleNamesByUsername(user.getUsername());
        authorizationInfo.setRoles(roleNames);
        Set<String> permissions = userService.findPermissionsByUsername(user.getUsername());
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        // 根据用户名和密码查询用户信息
        User user = userService.findByUsernameAndPassword(upToken.getUsername(), new String(upToken.getPassword()));
        if (user != null) {
            // 如果用户存在返回一个身份认证信息
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
            return authenticationInfo;
        }
        throw new UnknownAccountException("用户名或密码错误");
    }
}

以上代码中,MyRealm类中的doGetAuthenticationInfo方法用于根据用户名和密码查询用户信息,如果找到用户信息则返回一个身份认证信息。
doGetAuthorizationInfo方法用于根据PrincipalCollection对象获取当前用户的角色和权限信息,并添加到相应的授权信息中。

  1. 使用Shiro相关API实现身份验证和访问控制:
// 获取Subject对象
Subject subject = SecurityUtils.getSubject();
// 构造UsernamePasswordToken对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
    // 身份验证
    subject.login(token);
} catch (AuthenticationException e) {
    // 身份验证失败
}
if (subject.isAuthenticated()) {
    // 访问控制
    if (subject.hasRole("admin")) {
        // admin用户的操作
    }
    if (subject.isPermitted("user:create")) {
        // 创建用户操作
    }
}

以上代码中,使用SecurityUtils.getSubject()方法获取当前用户对象,使用UsernamePasswordToken构造方法构造身份认证信息。
通过subject.login(token)方法进行身份验证,subject.hasRole()和subject.isPermitted()方法进行访问控制。

示例1:使用Shiro实现用户登录认证

  1. 创建login.jsp文件,并添加一个简单的表单用于用户登录:
<form action="/login" method="post">
    <input type="text" name="username" placeholder="用户名">
    <input type="password" name="password" placeholder="密码">
    <input type="submit" value="登录">
</form>
  1. 在Spring应用程序中配置Shiro相关组件,并添加用户登录控制器:
@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest request) {
        // 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 构造UsernamePasswordToken对象
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            // 身份验证
            subject.login(token);
            // 身份验证成功跳转到首页
            return "redirect:/index";
        } catch (AuthenticationException e) {
            // 身份验证失败跳转到登录页面,显示错误信息
            request.setAttribute("error", "用户名或密码错误");
            return "login";
        }
    }
}
  1. 在MyRealm类中实现doGetAuthenticationInfo方法用于根据用户名和密码查询用户信息:
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    // 根据用户名和密码查询用户信息
    User user = userService.findByUsernameAndPassword(upToken.getUsername(), new String(upToken.getPassword()));
    if (user != null) {
        // 如果用户存在返回一个身份认证信息
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        return authenticationInfo;
    }
    throw new UnknownAccountException("用户名或密码错误");
}
  1. 运行应用程序并访问/login,输入用户名和密码进行登录认证。

示例2:使用Shiro实现角色授权和资源保护

  1. 在数据库中创建用户、角色和权限三张表,并添加测试数据:
CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL DEFAULT '',
  `password` varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `role` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `permission` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `user` (`id`, `username`, `password`) VALUES
    (1, 'admin', 'admin'),
    (2, 'user', 'user');

INSERT INTO `role` (`id`, `name`) VALUES
    (1, 'admin'),
    (2, 'user');

INSERT INTO `permission` (`id`, `name`) VALUES
    (1, 'user:read'),
    (2, 'user:create'),
    (3, 'user:update'),
    (4, 'user:delete');
  1. 在MyRealm类中实现doGetAuthorizationInfo方法,使用userService.findRoleNamesByUsername()和userService.findPermissionsByUsername()方法查询当前用户的角色和权限信息,并添加到authorizationInfo对象中:
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    User user = (User)principals.getPrimaryPrincipal();
    Set<String> roleNames = userService.findRoleNamesByUsername(user.getUsername());
    authorizationInfo.setRoles(roleNames);
    Set<String> permissions = userService.findPermissionsByUsername(user.getUsername());
    authorizationInfo.setStringPermissions(permissions);
    return authorizationInfo;
}
  1. 在Spring应用程序中配置Shiro相关组件,并添加用户列表控制器:
@Controller
public class UserController {
    @RequestMapping("/users")
    public String list() {
        // 访问控制,如果用户没有"admin"角色或"users:view"权限,则禁止访问
        Subject subject = SecurityUtils.getSubject();
        if (!subject.hasRole("admin") && !subject.isPermitted("users:view")) {
            throw new UnauthorizedException("没有访问权限");
        }
        // 查询用户列表,并返回到users.jsp页面
        List<User> userList = userService.findAll();
        return "users";
    }
}
  1. 在Spring应用程序中修改Shiro过滤器,使用perms和roles配置用户访问控制规则:
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm" />
    <property name="sessionManager" ref="sessionManager" />
</bean>

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="globalSessionTimeout" value="3600000" />
    <property name="deleteInvalidSessions" value="true" />
    <property name="sessionDAO" ref="sessionDAO" />
</bean>

<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
    <property name="cacheManager" ref="cacheManager" />
</bean>

<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
</bean>

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <property name="filterChainDefinitions">
        <value>
            /login.jsp = anon
            /logout = logout
            /users = authc, perms[users:view], roles[admin]
            /** = authc
        </value>
    </property>
    <property name="loginUrl" value="/login.jsp" />
    <property name="successUrl" value="/index.jsp" />
    <property name="unauthorizedUrl" value="/unauthorized.jsp" />
</bean>
  1. 运行应用程序并访问/users,如果当前用户没有"admin"角色或者"users:view"权限,则禁止访问;如果有访问权限,则显示用户列表。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java Apache Shiro安全框架快速开发详解流程 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • Mysql一主多从部署的实现步骤

    实现一主多从部署可以提高Mysql的可用性和读写性能。下面是具体的实现步骤。 步骤一:搭建Mysql主节点 安装Mysql数据库服务; 在主节点的Mysql配置文件my.cnf中开启binlog日志:log-bin=mysql-bin; 在配置文件中配置需要同步的数据库和表:binlog-do-db=database_name; 重启Mysql服务,使配置生…

    database 2023年5月22日
    00
  • JDBC连接mysql乱码异常问题处理总结

    JDBC连接MySQL乱码异常问题处理总结 问题描述 在使用JDBC连接MySQL数据库时,可能会出现乱码的异常情况,如下所示: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect string value: ‘\xCE\xB1\xCE\xBC\xCF\x80…’ for colu…

    database 2023年5月21日
    00
  • 在命令行下进行Oracle用户解锁的语句

    Sure,下面是在命令行下进行Oracle用户解锁的完整攻略: 步骤一:登录SQL Plus 在命令行界面下,通过以下命令登录SQL Plus: sqlplus / as sysdba 这里 / as sysdba 表示使用具有 SYSDBA 角色的特权用户连接到 Oracle 数据库。 步骤二:确认用户被锁 在 SQL Plus 下输入以下命令,确认要解锁…

    database 2023年5月21日
    00
  • MySQL如何查看建库建表语句

    MySQL是一种非常流行的关系型数据库管理系统。在开发和管理MySQL数据库时,查看建库建表语句是非常常见的需求。这里提供MySQL如何查看建库建表语句的完整攻略,详细步骤如下: 查看建库语句 使用SHOW语句查看建库语句 SHOW CREATE DATABASE database_name; 这里的database_name是你需要查看的数据库名称。执行以…

    database 2023年5月21日
    00
  • MySQL中的启动和关闭命令

    启动和关闭MySQL服务是日常MySQL维护工作中必不可少的操作。下面我将详细讲解MySQL中的启动和关闭命令。 启动MySQL 启动MySQL之前,需要打开命令行工具或者终端。在Windows上,可以通过点击开始菜单,搜索CMD并打开命令行工具。在Linux和macOS系统上,可以通过快捷键Ctrl+Alt+T或者在终端栏中输入Terminal来打开终端。…

    database 2023年5月21日
    00
  • DBMS 关系模型

    DBMS(Database Management System)是数据库管理系统的缩写,它是一种管理和操作数据库的软件系统。DBMS可以按照不同的数据模型来组织数据,其中,关系模型是最常用的一种数据模型。 关系模型是一种基于二维表的数据结构,它以表格的形式表达数据之间的关系。每一张表都有一个唯一的表名,而表中的每一行表示一个实体,每一列表示实体的属性。每一张…

    database 2023年3月27日
    00
  • SQL语句多表联查的实现方法示例

    下面是“SQL语句多表联查的实现方法示例”的完整攻略: 什么是SQL语句多表联查 SQL语句多表联查指的是在SQL语句中同时查询两个或多个表,并将它们的信息联合在一起展示。 SQL语句多表联查的实现方法 INNER JOIN INNER JOIN是最常用的多表联查方法之一。它会返回两个表中都存在的行。具体语法如下: SELECT * FROM table1 …

    database 2023年5月22日
    00
  • MySQL学习必备条件查询数据

    MySQL学习中,掌握条件查询数据操作是非常重要的一步。下面我为您详细讲解MySQL学习必备条件查询数据的完整攻略。 一、查询单个字段 查询单个字段的语法格式如下: SELECT 列名称 FROM 表名称; 其中,列名称表示需要查询的字段,可以是多个字段,每个字段之间用逗号隔开;表名称表示需要查询的表名。 示例一: 比如,我们需要查询users表中的name…

    database 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部