Shiro集成SpringMVC工程整合

来源:互联网 发布:java class.getname 编辑:程序博客网 时间:2024/06/06 06:43

Apache Shiro Framework 介绍

第一章:Shiro简介

1、1 Shiro框架简介

Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权。Shiro在JavaSE和JavaEE项目中都可以使用。它主要用来处理身份认证,授权,企业会话管理和加密等。

官网地址如下:http://shiro.apache.org/

Shiro的具体功能点如下:![屏幕快照 2017-08-25 下午4.24.25](屏幕快照 2017-08-25 下午4.24.25.png)

(1)身份认证/登录,验证用户是不是拥有相应的身份;
(2)授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
(3)会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
(4)加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
(5)Web支持,可以非常容易的集成到Web环境;

(6) Caching :缓存,存储用户登录之后的信息,拥有角色和权限不需要每次都去查

##### 1、2 Shiro主要有四个组件

  1. SecurityManager典型的 Facade,Shiro 通过它对外提供安全管理的各种服务。

  2. Authenticator对“Who are you ?”进行核实。通常涉及用户名和密码。这 个组件负责收集 principals 和 credentials,并将它们提交给应用系统。如果提交的 credentials 跟应用系统中提供的 credentials 吻合,就能够继续访问,否则需要重新提交 principals 和 credentials,或者直接终止访问。

  3. Authorizer身 份份验证通过后,由这个组件对登录人员进行访问控制的筛查,比如“who can do what”, 或者“who can do which actions”。Shiro 采用“基于 Realm”的方法,即用户(又称 Subject)、用户组、角色和 permission 的聚合体。

  4. Session Manager这个组件保证了异构客户端的访问,配置简单。它是基于 POJO/J2SE 的,不跟任何的客户端或者协议绑定。

    20160809110821940

同样的虚线框框圈着的是Shiro3大核心组件:

Subject :正与系统进行交互的人,或某一个第三方服务。所有 Subject 实例都被绑定到(且这是必须的)一个SecurityManager 上。
SecurityManager:Shiro 架构的心脏,用来协调内部各安全组件,管理内部组件实例,并通过它来提供安全管理的各种服务。当 Shiro 与一个 Subject 进行交互时,实质上是幕后的 SecurityManager 处理所有繁重的 Subject 安全操作。
Realms :本质上是一个特定安全的 DAO。当配置 Shiro 时,必须指定至少一个 Realm 用来进行身份验证和/或授权。Shiro 提供了多种可用的 Realms 来获取安全相关的数据。如关系数据库(JDBC),INI 及属性文件等。可以定义自己 Realm 实现来代表自定义的数据源。

第二章:Shiro之编码加密

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.sudojava.shiro</groupId>    <artifactId>shiro_java</artifactId>    <version>1.0-SNAPSHOT</version>    <build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <configuration>                    <source>1.8</source>                    <target>1.8</target>                </configuration>            </plugin>        </plugins>    </build>    <dependencies>        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-core</artifactId>            <version>1.2.3</version>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-simple</artifactId>            <version>1.6.1</version>            <scope>test</scope>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>        </dependency>    </dependencies></project>
2.1、关于shiro加密的说明

Shiro提供了base64和16进制字符串编码/解码的API支持,方便一些编码解码操作。Shiro内部的一些数据的存储/表示都使用了base64和16进制字符串,实现不同的加密算法如下:

产生随机的“盐值”算法

package com.sudojava.shiro.commons;import org.apache.shiro.SecurityUtils;import org.apache.shiro.crypto.RandomNumberGenerator;import org.apache.shiro.crypto.SecureRandomNumberGenerator;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.ByteSource;public class RandomNumberUtils {    //随机数的代码生成器    private static RandomNumberGenerator generator;    static {        generator = new SecureRandomNumberGenerator();    }    /**     * 获取工具类     * @return     */    public static ByteSource getByteSource(){        if (generator!=null){            return  generator.nextBytes();        }        return  null;    }}

各种不同的加密算法如下:

package com.sudojava.shiro.cryptography;import com.sudojava.shiro.commons.RandomNumberUtils;import org.apache.shiro.crypto.hash.*;public class CryptoUtils {    protected static Object getSalt() {        return RandomNumberUtils.getByteSource().toHex();    }    public static String cryptoObject(String source,String algorithm,int hashIterations) {        switch (algorithm) {            case "md5": {                Md5Hash md5Hash = new Md5Hash(source,getSalt(),hashIterations);                return  md5Hash.toHex();            }            case "md2":            {                Md2Hash md2Hash = new Md2Hash(source,getSalt(),hashIterations);                return md2Hash.toHex();            }            case "sha1":            {                Sha1Hash sha1Hash = new Sha1Hash(source,getSalt(),hashIterations);                return  sha1Hash.toHex();            }            case "sha256":            {                Sha256Hash sha256Hash = new Sha256Hash(source,getSalt(),hashIterations);                return  sha256Hash.toHex();            }            default:                return null;        }    }}

测试加密算法结果:

package com.sudojava.shiro.test;import com.sudojava.shiro.cryptography.CryptoUtils;import org.apache.shiro.crypto.hash.Md5Hash;import org.junit.Test;public class TestSimpleHash {    @Test    public void testMethod() {        String username = "admin";        String result1 = CryptoUtils.cryptoObject(username, "md5", 4);        System.out.println(result1);        String result2 = CryptoUtils.cryptoObject(username, "md2", 4);        System.out.println(result2);        String result3 = CryptoUtils.cryptoObject(username, "sha1", 4);        System.out.println(result3);    }}

第三章:Shiro身份认证

用户身份验证,在应用程序中做身份以及角色的认证。一般都是使用用户名和密码作为认证的凭据。

在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份:

principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。

credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。

最常见的principals和credentials组合就是用户名/密码了。

第一步:

配置shiro.ini文件,采用硬编码的方式提供认证信息

# =============================================================================# Tutorial INI configuration## Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)# =============================================================================# -----------------------------------------------------------------------------# Users and their (optional) assigned roles# username = password, role1, role2, ..., roleN# -----------------------------------------------------------------------------[users]root = secret, adminguest = guest, guestpresidentskroob = 12345, presidentdarkhelmet = ludicrousspeed, darklord, schwartzlonestarr = vespa, goodguy, schwartz

配置规则:

用户名 = 密码,角色1,角色2,角色3等

模拟用户登录情景

用户登录类:Authorization

package com.sudojava.shiro.authorization;import com.sudojava.shiro.domain.User;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class Authorization {    private static final transient Logger log = LoggerFactory.getLogger(Authorization.class);    private Factory<SecurityManager> factory;    private SecurityManager manager;    public Authorization(String shiro_ini) {        //获取SecurityManager工厂,加载shiro.ini文件        factory = new IniSecurityManagerFactory(shiro_ini);        //得到SecurityManager实例,并绑定给SecurityUtils        manager = factory.getInstance();    }    /**     * 模拟用户登录过程     *     * @param user     * @return     */    public boolean login(User user) {        boolean flag = false;        SecurityUtils.setSecurityManager(manager);        //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)        Subject currentUser = SecurityUtils.getSubject();        if (!currentUser.isAuthenticated()) {            UsernamePasswordToken token =                    new UsernamePasswordToken(user.getUsername(), user.getPassword());            token.setRememberMe(true);//记住用户登录信息            try {                currentUser.login(token);//执行登录操作,进行身份验证                flag = true;            } catch (UnknownAccountException e) {                log.info("未知用户账号异常");            } catch (IncorrectCredentialsException e) {                log.info("凭证不正确");            } catch (ExcessiveAttemptsException e) {                log.info("尝试认证次数多于系统指定次数");            } catch (AuthenticationException e) {                //所有认证异常的父类                log.info("其他未知错误!");            }        }        currentUser.logout();//用户登出操作        return flag;    }}

测试用户登录结果:

package com.sudojava.shiro.authorization;import com.sudojava.shiro.domain.User;import org.junit.Before;import org.junit.Test;public class TestAuthorization {    private Authorization authorization;    @Before    public void init(){        authorization = new Authorization("classpath:shiro.ini");    }    @Test    public void login(){        User user = new User();        user.setPassword("guest");        user.setUsername("guest");       boolean flag =  authorization.login(user);       if (flag){           System.out.println("登录成功");       }else{           System.out.println("登录失败");       }    }}

第四章:Shiro 授权机制

在shiro中规定了授权的基本对象包括:Subject、Role和Permission和访问资源等四个主体对象。

Subject:主体

主体,指的是访问应用的用户,一般通知User对象。

Resource:资源

通常是指工程下资源模块,也可以指定特定的业务。

Role:角色

角色代表主体的身份特征,一般一种角色下可以拥有多种主体,所以是一对多的关系,例如:超级管理员、经理、CTO等。

Permission:权限

即指定授予主体操作某一些资源的权力,比如,查看、删除和修改的权力等。

授权方式

Shiro授权方式分为三种:

1、Java代码实现

通过Subject对象实现

2、注解实现

通过@RequireXXX实现

3、在web页面上实现

通过实现

案例讲解

模拟用户登录之后,判断该用户是否拥有一定权限,如果该用户有指定的权限,那么可以执行删除或者修改功能

配置shiro.ini文件

# =============================================================================# Tutorial INI configuration## Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)# =============================================================================# -----------------------------------------------------------------------------# Users and their (optional) assigned roles# username = password, role1, role2, ..., roleN# -----------------------------------------------------------------------------[users]root = secret, adminguest = guest, guestpresidentskroob = 12345, presidentdarkhelmet = ludicrousspeed, darklord, schwartzlonestarr = vespa, goodguy, schwartzjack = 123456,admin# -----------------------------------------------------------------------------# Roles with assigned permissions# roleName = perm1, perm2, ..., permN# -----------------------------------------------------------------------------[roles]admin = user:create,user:update,user:deleteschwartz = lightsaber:*goodguy = winnebago:drive:eagle5

核心BasicRole类:

我们声明一个抽象类,指定登录方法为抽象的方法

package com.sudojava.shiro.role;import com.sudojava.shiro.authorization.Authorization;import com.sudojava.shiro.domain.User;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public abstract class BasicRole<T> {    private Factory<SecurityManager> factory;    private SecurityManager manager;    public BasicRole(String shiro_ini) {        //获取SecurityManager工厂,加载shiro.ini文件        factory = new IniSecurityManagerFactory(shiro_ini);        //得到SecurityManager实例,并绑定给SecurityUtils        manager = factory.getInstance();    }    public Factory<SecurityManager> getFactory() {        return factory;    }    public void setFactory(Factory<SecurityManager> factory) {        this.factory = factory;    }    public SecurityManager getManager() {        return manager;    }    public void setManager(SecurityManager manager) {        this.manager = manager;    }    public abstract boolean login(T t);}

核心登录LoginRole类

package com.sudojava.shiro.role;import com.sudojava.shiro.authorization.Authorization;import com.sudojava.shiro.domain.User;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class LoginRole extends BasicRole<User> {    private static final transient Logger log = LoggerFactory.getLogger(Authorization.class);    public LoginRole(String shiro_ini) {        super(shiro_ini);    }    @Override    public boolean login(User user) {        SecurityUtils.setSecurityManager(getManager());        Subject subject = SecurityUtils.getSubject();        if (!subject.isAuthenticated()) {            UsernamePasswordToken token =                    new UsernamePasswordToken(user.getUsername(), user.getPassword());            token.setRememberMe(true);            try {                subject.login(token);                if (subject.hasRole("admin")) {                    log.info("该用户拥有admin角色身份");                    if (subject.isPermitted("user:delete")) {                        log.info("该用户具有删除选项功能");                        subject.execute(new Runnable() {                            @Override                            public void run() {                                try {                                    Thread.sleep(3000);                                    log.info("执行删除操作");                                } catch (InterruptedException e) {                                    e.printStackTrace();                                }                            }                        });                    }                }                return true;            } catch (UnknownAccountException e) {                log.info("未知用户");            }        }        return false;    }}

核心测试类

package com.sudojava.shiro.role;import com.sudojava.shiro.domain.User;import org.junit.Before;import org.junit.Test;public class TestRole {    private LoginRole loginRole;    @Before    public void  init(){        loginRole = new LoginRole("classpath:shiro.ini");    }    @Test    public void test(){        User user = new User();        user.setUsername("root");        user.setPassword("secret");        boolean flag = loginRole.login(user);        System.out.println(flag);    }}

关于Shiro.ini配置文件的说明

~~~ini

—————————————————————————–

Users and their (optional) assigned roles

username = password, role1, role2, …, roleN

—————————————————————————–

[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz
jack = 123456,admin
~~~

配置shiro.ini用户如下规则:

[users]是标志用户信息,规则如下:

用户名 = 密码,角色1,角色2,角色3……

分析数据结构:一个用户可以拥有多个角色

~~~ini

—————————————————————————–

Roles with assigned permissions

roleName = perm1, perm2, …, permN

—————————————————————————–

[roles]

admin = user:create,user:update,user:delete
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5

~~~

[roles] 是标志用户角色拥有什么权限,规则如下:

资源:用户操作

例如:

admin = user:view

admin 拥有user的查看权限

admin = user:create,user:update,user:delete

admin 拥有user的创建和修改、删除权限

admin =user:*

admin 拥有user下的所有权限

admin = system:user :create, delete,view,find

admin 拥有system:user 下的CRUD功能

第五章:Shiro Realm认证流程

在Shiro中Realm(域)可以访问特定的应用程序安全实体(如:用户、角色和权限)以确定身份验证和授权操作。

Realm通常和数据源有关系,例如关系型数据库、文件系统等,具有一对一的对应关系。Realm接口实现使用特定

数据源的API接口访问数据,也就是我们可以在数据库中直接定义 用户表角色表和权限表等,我们可以使用JDBC、Hibernate、JPA的规范访问,Realm本质上是数据访问层的DAO。

由于每个应用程序不同,用户和角色等安全数据可以以多种方式进行表示。 Shiro尝试尽可能保持非侵入性的开发哲学 - 它不要求您实现或扩展任何用户,组或角色接口或类

大多数用户不会直接实现Realm接口,而是扩展其中一个子类AuthenticatingRealm或AuthorizingRealm,大大降低了从头开始实现Realm的工作量。

AuthenticatingRealm类的介绍

该类主要是实现了验证模块的信息,通过它可以实现一系列用户登录校验和角色判断等功能,通常该类是配合CacheManager一起使用的,后面我们在详细介绍。

代码示例

第一步配置shiro_realm.ini文件

[main]#声明一个realmmyRealm1 = com.sudojava.shiro.realm.LoginRealm#指定securityManager的realms实现securityManager.realms=$myRealm1

第二步继承AuthenticatingRealm类

package com.sudojava.shiro.realm;import org.apache.shiro.authc.*;import org.apache.shiro.realm.AuthenticatingRealm;/** * 可以使用Realm获取数据库的基本信息, * 包括User表、权限表、和角色表 */public class LoginRealm extends AuthenticatingRealm {    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {        //取出用户名和密码        String username = token.getPrincipal().toString();        String password = new String((char[]) token.getCredentials());        if(!"zhang".equals(username)) {            throw new UnknownAccountException(); //如果用户名错误        }        if(!"123".equals(password)) {            throw new IncorrectCredentialsException(); //如果密码错误        }        return new SimpleAuthenticationInfo(username,password,getName());    }}

备注:采用硬编码的方式,模拟数据库的账号为:zhang 密码为:123

第三步Login类的实现

package com.sudojava.shiro.realm;import com.sudojava.shiro.authorization.Authorization;import com.sudojava.shiro.domain.User;import com.sudojava.shiro.role.BasicRole;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class Login extends BasicRole<User> {    private static final  Logger log = LoggerFactory.getLogger(Authorization.class);    public Login(String shiro_ini) {        super(shiro_ini);    }    @Override    public boolean login(User user) {        SecurityUtils.setSecurityManager(getManager());        Subject subject = SecurityUtils.getSubject();        if (!subject.isAuthenticated()){            UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());            token.setRememberMe(true);            try {               subject.login(token);               return  true;            }catch (UnknownAccountException e){                log.info("账号不匹配");            }        }        return false;    }}

第四步测试类的实现

package com.sudojava.shiro.realm;import com.sudojava.shiro.domain.User;import org.junit.Before;import org.junit.Test;public class TestRealm {    private Login login;    @Before    public void init(){        login = new Login("classpath:shiro_realm.ini");    }    @Test    public void login(){        User user = new User();        user.setUsername("zhang");        user.setPassword("123");        boolean flag = login.login(user);        System.out.println(flag);    }}

第六章:Shiro 使用JdbcRealm进行验证

我们先来看看Shiro的认证流程

wKiom1ePJu3CpsHXAAJXWZSp3ME963

从上面的继承关系图,我们可以看出来一般都是继承AuthorizingRealm就可以了,自带缓存的功能。

Shiro Realm主要默认实现:

  • org.apache.shiro.realm.text.IniRealm:
    ​ 通过ini文件配置进行验证,

    ​ [users]部分指定用户名/密码及其角色;

    ​ [roles]部分指定角色即权限信息;

  • org.apache.shiro.realm.text.PropertiesRealm:
    ​ user.username=password,role1,role2 标志用户名密码和角色
    ​ role.role1=permission1,permission2 标志角色和权限信息

  • org.apache.shiro.realm.jdbc.JdbcRealm:

    我们可以通过创建对应的表,使用sql语句查询出来对应的信息:

    获取用户密码:“select“select password from users where username = ?”,
    获取用户密码及盐:“select password, password_salt from users where username = ?”
    获取用户角色:“select role_name from user_roles where username = ?”
    获取角色对应的权限信息:“select permission from roles_permissions where role_name = ?”
    也可以调用相应的api进行自定义sql。

使用JdbcRealm进行验证示例步骤:

第一步:创建shiro-jdbc-realm.ini文件

[main]# 配置JDBC数据库连接dataSource=com.alibaba.druid.pool.DruidDataSourcedataSource.driverClassName=com.mysql.jdbc.DriverdataSource.url=jdbc:mysql://localhost:3306/shirodataSource.username=rootdataSource.password=root# JdbcRealmjdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm# 允许授权查询jdbcRealm.permissionsLookupEnabled = truejdbcRealm.dataSource=$dataSource#编写查询数据库的SQL语句jdbcRealm.authenticationQuery = select password from users where username = ?jdbcRealm.userRolesQuery = select a.role_name from user_roles a,users b where a.users_id = b.id  and  b.username = ?jdbcRealm.permissionsQuery =select a.permission FROM roles_permissions a,user_roles b  where b.role_id = a.user_roles_role_id and b.role_name = ?securityManager.realms=$jdbcRealm

第二步:在pom.xml文件中添加DataSource,使用的是阿里巴巴的数据驱动

<!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid</artifactId>    <version>1.1.0</version></dependency><!-- 添加mysql数据驱动 --><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>5.1.40</version></dependency>

第三步:创建用户表users、user_roles、roles_permissions表

~~~mysql
CREATE TABLE IF NOT EXISTS shiro.users (
id INT NOT NULL,
username VARCHAR(100) NULL,
password VARCHAR(100) NULL,
password_salt VARCHAR(100) NULL,
PRIMARY KEY (id))
ENGINE = InnoDB

CREATE TABLE IF NOT EXISTS shiro.user_roles (
role_id INT NOT NULL,
role_name VARCHAR(100) NULL,
users_id INT NOT NULL,
PRIMARY KEY (role_id),
INDEX fk_user_roles_users1_idx (users_id ASC),
CONSTRAINT fk_user_roles_users1
FOREIGN KEY (users_id)
REFERENCES shiro.users (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB

CREATE TABLE IF NOT EXISTS shiro.roles_permissions (
permission VARCHAR(100) NULL,
p_id INT NOT NULL,
user_roles_role_id INT NOT NULL,
PRIMARY KEY (p_id),
INDEX fk_roles_permissions_user_roles1_idx (user_roles_role_id ASC),
CONSTRAINT fk_roles_permissions_user_roles1
FOREIGN KEY (user_roles_role_id)
REFERENCES shiro.user_roles (role_id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
~~~

备注:请校验数据库的名称。

第四步:创建JDBCRealm相关的类

package com.sudojava.shiro.jdbcrealm;import com.sudojava.shiro.authorization.Authorization;import com.sudojava.shiro.domain.User;import com.sudojava.shiro.basic.BasicShiro;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authz.Permission;import org.apache.shiro.authz.permission.WildcardPermission;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class LoginForJdbcRealm  extends BasicShiro<User> {    private static final Logger log = LoggerFactory.getLogger(Authorization.class);    public LoginForJdbcRealm(String shiro_ini) {        super(shiro_ini);    }    @Override    public boolean login(User user) {        SecurityUtils.setSecurityManager(getManager());        Subject subject = SecurityUtils.getSubject();        if (!subject.isAuthenticated()){            UsernamePasswordToken token  =                    new UsernamePasswordToken(user.getUsername(),user.getPassword());            try {                subject.login(token);                token.setRememberMe(true);                if (subject.hasRole("manager")){                    log.info("该用户拥有 manager 角色");                    subject.checkPermission("delete");                    if (subject.isPermitted("delete")){                        log.info("该用户具有删除的权限");                        subject.execute(new Runnable() {                            @Override                            public void run() {                                try {                                    Thread.sleep(3000);                                    log.info("删除资源中......");                                } catch (Exception e) {                                    e.printStackTrace();                                }                            }                        });                    }                }                return true;            } catch (UnknownAccountException e) {               log.info(e.getMessage()+"账号名有误");            }        }        return false;    }}

模拟用户登录操作

package com.sudojava.shiro.jdbc;import com.sudojava.shiro.domain.User;import com.sudojava.shiro.jdbcrealm.LoginForJdbcRealm;import org.junit.Before;import org.junit.Test;public class TestForJdbc {    private LoginForJdbcRealm realm;    @Before    public void setup(){        realm = new LoginForJdbcRealm("classpath:shiro-jdbc-realm.ini");    }    @Test    public void login(){        User user = new User();        user.setPassword("123");        user.setUsername("admin");        boolean flag = realm.login(user);        System.out.println(flag);    }}

第七章:使用原生的Java代码对Realm类进行校验和授权操作

在shiro中我们可以采用Java代码对JdbcRealm进行封装,直接在登录模块进行校验操作。

手动封装Java类

package com.sudojava.shiro.nativeRealm;import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.jdbc.JdbcRealm;public class RealmDataSource {    private MysqlDataSource dataSource;    private DefaultSecurityManager securityManager;    private JdbcRealm jdbcRealm;    public RealmDataSource() {        try {            dataSource = new MysqlDataSource();            dataSource.setUser("root");            dataSource.setPassword("root");            dataSource.setServerName("localhost");            dataSource.setLoginTimeout(2);            dataSource.setUrl("jdbc:mysql://localhost:3306/shiro");            jdbcRealm = new JdbcRealm();            jdbcRealm.setDataSource(dataSource);            jdbcRealm.setPermissionsLookupEnabled(true);            //验证            String authentication_sql = "select password from users where username = ?";            jdbcRealm.setAuthenticationQuery(authentication_sql);            //验证角色            String user_roles_sql = "select a.role_name from user_roles a,users b where a.users_id = b.id  and  b.username = ?";            jdbcRealm.setUserRolesQuery(user_roles_sql);            String permission_sql = "select a.permission FROM roles_permissions a,user_roles b  where b.role_id = a.user_roles_role_id and b.role_name = ?";            jdbcRealm.setPermissionsQuery(permission_sql);            securityManager = new DefaultSecurityManager(jdbcRealm);        } catch (Exception e) {            e.printStackTrace();        }    }    public DefaultSecurityManager getSecurityManager() {        return securityManager;    }    /**     * @return     */    public MysqlDataSource getDataSource() {        if (dataSource != null) {            return dataSource;        }        return null;    }}

模拟用户登录操作

package com.sudojava.shiro.nativeRealm;import com.sudojava.shiro.authorization.Authorization;import com.sudojava.shiro.domain.User;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class NativeLogin {    private static final Logger log = LoggerFactory.getLogger(Authorization.class);    private RealmDataSource dataSource;    public NativeLogin() {        dataSource = new RealmDataSource();    }    public boolean login(User user) {        boolean flag = false;        SecurityUtils.setSecurityManager(dataSource.getSecurityManager());        Subject subject = SecurityUtils.getSubject();        if (!subject.isAuthenticated()) {            UsernamePasswordToken token =                    new UsernamePasswordToken(user.getUsername(), user.getPassword());            token.setRememberMe(true);            try {                subject.login(token);                System.out.println("login successfully");                flag = true;                if (subject.hasRole("manager")){                    log.info("该用户拥有 manager 角色");                    subject.checkPermission("delete");                    if (subject.isPermitted("delete")){                        log.info("该用户具有删除的权限");                        subject.execute(new Runnable() {                            @Override                            public void run() {                                try {                                    Thread.sleep(3000);                                    log.info("删除资源中......");                                } catch (Exception e) {                                    e.printStackTrace();                                }                            }                        });                    }                }            } catch (UnknownAccountException e) {                e.printStackTrace();            }        }        return flag;    }}

测试Java类

package com.sudojava.shiro.nativerealm;import com.sudojava.shiro.domain.User;import com.sudojava.shiro.nativeRealm.NativeLogin;import org.junit.Before;import org.junit.Test;public class TestNative {    private NativeLogin nativeLogin;    @Before    public void setup(){        nativeLogin = new NativeLogin();    }    @Test    public void loginUser(){        User user = new User();        user.setPassword("123");        user.setUsername("admin");        boolean flag = nativeLogin.login(user);        System.out.println(flag);    }}

第八章:Shiro Web整合以及实现等验证操作

Shiro提供了与Web集成环境的安全应用支持,

我们在Web工程下的web.xml配置简单的ShiroFilter来控制所有的URL请求,并且根据请求进行转发,

其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter类似于如Strut2/SpringMVC这种web框架的前端控制器,其是安全控制的入口点,其负责读取配置(如ini配置文件),然后判断URL是否需要登录/权限等工作。

原创粉丝点击