Hello shiro基础知识整理---shiro基础篇(附JWT链接)

转载请注明出处:
牵手生活--简书:笔记是整理思路方式,分享是一个美德,牵手是我的生活方式

SpringBoot+JWT实战(附源码)--今日头条大神


shiro概述参见shiro(java安全框架)

shiro(java安全框架)

shiro整体架构

认识shiro需要理解的内容


认识shiro

在idea中创建一个maven javaweb工程HelloShiro

配置pom.xml文件引入shiro核心包和junit

    <dependencies>
        <!--导入shiro包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!--导入测试包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
        </dependency>


    </dependencies>

shiro认证

创建一个单元测试类(junit)AuthenticationTest.java,并测试

模拟认证请求的过程


shiro认证过程
shiro认证单元测试结果
package com.younghare.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

public class AuthenticationTest {

    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before //所以测试方法运行前,都会运行
    public void addUser(){
        simpleAccountRealm.addAccount("Mark","123456");
    }

    @Test
    public void testAuthentication(){
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);  //设置Realm到环境中

        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("Mark","123456");

        subject.login(taken);//登录认证数据


        boolean  isAuthenticated = subject.isAuthenticated();
        System.out.println("认证的结果是:"+isAuthenticated);

        //退出登录
        subject.logout();
        System.out.println("logout后认证的结果是:"+subject.isAuthenticated());

    }
    
}

Shiro授权

shiro授权过程

修改单元测试,并查看结果


检查角色结果
public class AuthenticationTest {

    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before //所以测试方法运行前,都会运行
    public void addUser(){
        simpleAccountRealm.addAccount("Mark","123456","admin","user"); //第3个参数开始是角色
    }

    @Test
    public void testAuthentication(){
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);  //设置Realm到环境中

        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("Mark","123456");

        subject.login(taken);//登录认证数据


        boolean  isAuthenticated = subject.isAuthenticated();
        System.out.println("认证的结果是:"+isAuthenticated);

        subject.checkRole("admin1");//判断用户是否有admin的角色,可同时检查多个角色

    }  
}

IniRealm讲解

创建IniRealm的配置文件user.ini


user.ini内容
[users]
Mark = 123456,admin
[roles]
admin=user:delete

创建一个单元测试类(junit)IniRealmTest.java,并测试

public class IniRealmTest {
    @Test
    public void testAuthentication(){
        IniRealm iniRealm = new IniRealm("classpath:user.ini");
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);

        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("Mark","123456");
        subject.login(taken);//登录认证数据

        System.out.println("认证的结果是:"+subject.isAuthenticated());
        subject.checkRole("admin");

        subject.checkPermission("user:update");//是否具备用户删除的权限,配置信息在user.ini文件中
    }

}

目录结构
IniRealm单元测试结果

JdbcRealm讲解

在pom.xml中添加对mysql 和数据源druid的引入
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>

        <!--引入数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
在mysql数据库中创建对应的表users,结构如下
auth库的users表结构及数据

其他表的机构可以参考JdbcRealm源码的默认sql语句部分

编辑测试用例IniRealmTest.java 并测试
public class IniRealmTest {
    DruidDataSource dataSource = new DruidDataSource ();
    {
        dataSource.setUrl("jdbc:mysql://47.**.**.27:3306/auth?serverTimezone=UTC");
        //dataSource.setUrl("jdbc:mysql://localhost:3306/auth?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("你的密码");

    }

    
    @Test
    public void testAuthentication(){
        JdbcRealm jdbcRealm = new JdbcRealm();
        /*要首先建一个test的数据库,然后建一个users(username,password)的表,然后插入数据(‘Mark’,'123456)才行*/
        jdbcRealm.setDataSource(dataSource);//设置数据源

        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);
        jdbcRealm.setPermissionsLookupEnabled(true);//默认jdbcRealm不会去查询权限数据


        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("Mark","123456");
        subject.login(taken);//登录认证数据

        System.out.println("认证的结果是:"+subject.isAuthenticated());
        //subject.checkRole("admin"); 

    }

}

JdbcRealm源码中默认的sql查询语句

里面有对应默认表
问题
现在的问题是我们并设置查询语句呀,看看JdbcRealm的源码发现里面有默认的查询语句

JdbcRealm源码中默认的sql查询语句

所以我们应该根据默认的语句创建几张对应的表users、user_roles、roles_permissions、user_roles

idea配置database连接mysql

其他配置如:


image.png

创建test_user表,并添加数据


test_user表与数据

创建test_user_role表,并添加数据


test_user_role表结构与数据

IniRealmTest的testAuthentication方法修改如下


测试方法修改
  
    @Test
    public void testAuthentication(){
        JdbcRealm jdbcRealm = new JdbcRealm();
        /*要首先建一个test的数据库,然后建一个users(username,password)的表,然后插入数据(‘Mark’,'123456)才行*/
        jdbcRealm.setDataSource(dataSource);//设置数据源
        //jdbcRealm.setPermissionsLookupEnabled(true);//默认jdbcRealm不会去查询权限数据

        //不采用jdbcRealm默认表的情况,需要设置sql语句
        //SELECT PASSWORD FROM test_user WHERE user_name = "younghare"
        String sql = "SELECT PASSWORD FROM test_user WHERE user_name = ?";
        jdbcRealm.setAuthenticationQuery(sql);
        //sql语句的写法参考JdbcRealm源码
        String sqlRole = "SELECT role_name FROM test_user_role where user_name = ?";
        jdbcRealm.setUserRolesQuery(sqlRole);
        


        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);

        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("younghare","741852");
        subject.login(taken);//登录认证数据

        System.out.println("认证的结果是:"+subject.isAuthenticated());
        subject.checkRole("admin");

    }

IntelliJ IDEA中如何显示和关闭----工具栏,目录栏,

自定义Realm(需要继承AuthorizingRealm,实现doGetAuthorizationInfo和doGetAuthenticationInfo接口)

自定义CustomRealm.java
package com.younghare.shiro.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class CustomRealm extends AuthorizingRealm {
    /*模拟用户的数据库信息*/
    Map<String ,String> userMap = new HashMap<>(16);
    {
        userMap.put("younghare","123456");
        userMap.put("xiaoming","654321");
        super.setName("customRealm");//设置自己的realmName

    }

    @Override //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String userName = (String) principalCollection.getPrimaryPrincipal();
        //从数据库或缓冲中获得角色数据
        Set<String> roles = getRolesByUserName(userName);
        //从数据库或缓冲中获得权限数据
        Set<String> permissions = getPermissionsByUserName(userName);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(permissions);
        simpleAuthorizationInfo.setRoles(roles);

        return simpleAuthorizationInfo;
    }

    /**
     * 模拟用户权限数据
     * @param userName
     * @return
     */
    private Set<String> getPermissionsByUserName(String userName) {
        Set<String> sets = new HashSet<>();
        sets.add("user:myAdd");
        sets.add("user:delete");
        sets.add("user:update");
        return sets;

    }

    /**
     * 模拟角色数据
     * @param userName
     * @return
     */
    private Set<String> getRolesByUserName(String userName) {
        Set<String> sets = new HashSet<>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }

    @Override //认证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        /*从主体传来的认证信息中,获得用户名*/
        String userName = (String) authenticationToken.getPrincipal();
        /*通过用户名到数据库中获取凭证*/
        String password = getPasswordByUserName(userName);
        if (password == null){
            return null;
        }

        SimpleAuthenticationInfo authenticationInfo
                = new SimpleAuthenticationInfo("younghare",password ,"customRealm");

        return authenticationInfo;
    }

    /**
     * 模拟数据库操作
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName) {

        return userMap.get(userName);
    }
}


编译自定义realm的测试类CustomRealmTest.java

public class CustomRealmTest {

    @Test
    public void testAuthentication(){

        CustomRealm customRealm = new CustomRealm();
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);//设置自定义realm


        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("younghare","123456");
        subject.login(taken);//登录认证数据

        System.out.println("认证的结果是:"+subject.isAuthenticated());
        subject.checkRole("admin");
        subject.checkPermission("user:myadd");//是否具备用户update的权限
    }
}

Shiro加密

shiro散列配置
  • HashedCredentialsMatcher
  • 自定义Realm中使用散列
  • 盐的使用(加盐处理)
调用时为shiro添加加密算法

模拟加密的数据

如果有加盐处理还需要添加盐的处理

shiro加盐处理
认证方法中对加盐设置

自定义realm的加密&加盐CustomRealmJM.java


public class CustomRealmJM extends AuthorizingRealm {
    /*模拟用户的数据库信息*/
    Map<String ,String> userMap = new HashMap<>(16);
    {

        //Md5Hash md5Hash = new Md5Hash("123456");//==e10adc3949ba59abbe56e057f20f883e
        Md5Hash md5Hash = new Md5Hash("123456","younghare");//加盐:younghare处理
        userMap.put("younghare",md5Hash.toString());

        userMap.put("xiaoming","654321");
        super.setName("customRealm");//设置自己的realmName

    }

    @Override //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String userName = (String) principalCollection.getPrimaryPrincipal();
        //从数据库或缓冲中获得角色数据
        Set<String> roles = getRolesByUserName(userName);
        //从数据库或缓冲中获得权限数据
        Set<String> permissions = getPermissionsByUserName(userName);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(permissions);
        simpleAuthorizationInfo.setRoles(roles);

        return simpleAuthorizationInfo;
    }

    /**
     * 模拟用户权限数据
     * @param userName
     * @return
     */
    private Set<String> getPermissionsByUserName(String userName) {
        Set<String> sets = new HashSet<>();
        sets.add("user:myAdd");
        sets.add("user:delete");
        sets.add("user:update");
        return sets;

    }

    /**
     * 模拟角色数据
     * @param userName
     * @return
     */
    private Set<String> getRolesByUserName(String userName) {
        Set<String> sets = new HashSet<>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }

    @Override //认证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        /*从主体传来的认证信息中,获得用户名*/
        String userName = (String) authenticationToken.getPrincipal();
        /*通过用户名到数据库中获取凭证*/
        String password = getPasswordByUserName(userName);
        if (password == null){
            return null;
        }

        SimpleAuthenticationInfo authenticationInfo
                = new SimpleAuthenticationInfo("younghare",password,"customRealm");

        //如果有对shiro加密并加盐了,则需要添加加盐的处理
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("younghare"));

        return authenticationInfo;
    }

    /**
     * 模拟数据库操作
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName) {
        System.out.println(userName+":"+userMap.get(userName));

        return userMap.get(userName);
    }


}

测试用例的加密&加盐处理CustomRealmJmTest.java


public class CustomRealmJmTest {

    @Test
    public void testAuthentication(){

        CustomRealmJM customRealmJM = new CustomRealmJM();
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealmJM);//设置自定义realm

        /*shiro加密处理*/
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");//设置加密算法的名称
        matcher.setHashIterations(1);//设置加密算法的次数
        customRealmJM.setCredentialsMatcher(matcher);;


        //设置提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);  //设置环境
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken taken = new UsernamePasswordToken("younghare","123456");
        subject.login(taken);//登录认证数据

        System.out.println("认证的结果是:"+subject.isAuthenticated());
/*
        subject.checkRole("admin");
        subject.checkPermission("user:myadd");//是否具备用户update的权限
*/
    }

    @Test  //获取123456的md5值
    public  void testgetMd5(){
        Md5Hash md5Hash = new Md5Hash("123456");
        System.out.println(md5Hash.toString());
    }

    @Test //获取md5加盐
    public  void testgetMd5_jy(){
        //结果值是:b0d6977b961b5f0823a69a4adf9aef80
        Md5Hash md5Hash = new Md5Hash("123456","younghare");
        System.out.println(md5Hash.toString());
    }

}

加盐密码保存的最通用方法是?

拖库本来是数据库领域的术语,指从数据库中导出数据。到了[黑客攻击]泛滥的今天,它被用来指网站遭到入侵后,黑客窃取其数据库。


另开一文Hello shiro+springmvc实例--shiro加强篇

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容