Shiro学习配置

2 篇文章 0 订阅

Shiro学习配置

简介:Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

shiro实现认证

Shiro.ini

#用户
[users]
#用户zhang的密码是123,此用户具有role1和role2两个角色
zhangsan=123,role1,role2
wangwu2=123,role1,role3
wangwu3=123,role1
wangwu4=123,role1,role2
#权限
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create
#全部匹配(超级用户)
role4=*:*
#此方法用于没有设置defaultSecurityManager.setRealm(userRealm);自定义realm
[main]
#创建useRealm对象
useRealm=com.test.shiro.UserRealm
#将当前对象传给安全管理器
SecurityManager=org.apache.shiro.mgt.DefaultSecurityManager
SecurityManager.realm=$userRealm

log4j

log4j.rootLogger=INFO,consoleAppender,logfile,MAIL
log4j.addivity.org.apache=true
#ConsoleAppender,控制台输出
#FileAppender,文件日志输出
#SMTPAppender,发邮件输出日志
#SocketAppender,Socket 日志
#NTEventLogAppender,Window NT 日志
#SyslogAppender,
#JMSAppender,
#AsyncAppender,
#NullAppender
#文件输出:RollingFileAppender
#log4j.rootLogger = INFO,logfile
log4j.appender.logfile = org.apache.log4j.RollingFileAppender
log4j.appender.logfile.Threshold = INFO
# 输出以上的 INFO 信息
log4j.appender.logfile.File = INFO_log.html
#保存 log 文件路径
#Log4j 从入门到详解
10
log4j.appender.logfile.Append = true
# 默认为 true,添加到末尾,false 在每次启动时进行覆盖
log4j.appender.logfile.MaxFileSize = 1MB
# 一个 log 文件的大小,超过这个大小就又会生成 1 个日志 # KB ,MB,GB
log4j.appender.logfile.MaxBackupIndex = 3
# 最多保存 3 个文件备份
log4j.appender.logfile.layout = org.apache.log4j.HTMLLayout
# 输出文件的格式
log4j.appender.logfile.layout.LocationInfo = true
#是否显示类名和行数
log4j.appender.logfile.layout.Title=title:提醒您:系统发生了严重错误
#html 页面的 < title >
############################## SampleLayout ####################################
# log4j.appender.logfile.layout = org.apache.log4j.SampleLayout
############################## PatternLayout ###################################
# log4j.appender.logfile.layout = org.apache.log4j.PatternLayout
# log4j.appender.logfile.layout.ConversionPattern =% d % p [ % c] - % m % n % d
############################## XMLLayout #######################################
# log4j.appender.logfile.layout = org.apache.log4j.XMLLayout
# log4j.appender.logfile.layout.LocationInfo = true #是否显示类名和行数
############################## TTCCLayout ######################################
# log4j.appender.logfile.layout = org.apache.log4j.TTCCLayout
# log4j.appender.logfile.layout.DateFormat = ISO8601
#NULL, RELATIVE, ABSOLUTE, DATE or ISO8601.
# log4j.appender.logfile.layout.TimeZoneID = GMT - 8 : 00
# log4j.appender.logfile.layout.CategoryPrefixing = false ##默认为 true 打印类别名
# log4j.appender.logfile.layout.ContextPrinting = false ##默认为 true 打印上下文信息
# log4j.appender.logfile.layout.ThreadPrinting = false ##默认为 true 打印线程名
# 打印信息如下:
#2007 - 09 - 13 14 : 45 : 39 , 765 [http - 8080 - 1 ] ERROR com.poxool.test.test -
#error 成功关闭链接
###############################################################################
#每天文件的输出:DailyRollingFileAppender
#log4j.rootLogger = INFO,errorlogfile
log4j.appender.errorlogfile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.errorlogfile.Threshold = ERROR
log4j.appender.errorlogfile.File = ../logs/ERROR_log
log4j.appender.errorlogfile.Append = true
#默认为 true,添加到末尾,false 在每次启动时进行覆盖
log4j.appender.errorlogfile.ImmediateFlush = true
#直接输出,不进行缓存
# ' . ' yyyy - MM: 每个月更新一个 log 日志
# ' . ' yyyy - ww: 每个星期更新一个 log 日志
# ' . ' yyyy - MM - dd: 每天更新一个 log 日志
# ' . ' yyyy - MM - dd - a: 每天的午夜和正午更新一个 log 日志
# ' . ' yyyy - MM - dd - HH: 每小时更新一个 log 日志
# ' . ' yyyy - MM - dd - HH - mm: 每分钟更新一个 log 日志
#Log4j 从入门到详解
#11
log4j.appender.errorlogfile.DatePattern = ' . ' yyyy - MM - dd ' .log '
#文件名称的格式
log4j.appender.errorlogfile.layout = org.apache.log4j.PatternLayout
log4j.appender.errorlogfile.layout.ConversionPattern =%d %p [ %c] - %m %n %d
#控制台输出:
#log4j.rootLogger = INFO,consoleAppender
log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.Threshold = ERROR
log4j.appender.consoleAppender.layout = org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern =%d %-5p %m %n
log4j.appender.consoleAppender.ImmediateFlush = true
# 直接输出,不进行缓存
log4j.appender.consoleAppender.Target = System.err
# 默认是 System.out 方式输出
#发送邮件:SMTPAppender
#log4j.rootLogger = INFO,MAIL
log4j.appender.MAIL = org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold = INFO
log4j.appender.MAIL.BufferSize = 10
log4j.appender.MAIL.From = yourmail@gmail.com
log4j.appender.MAIL.SMTPHost = smtp.gmail.com
log4j.appender.MAIL.Subject = Log4J Message
log4j.appender.MAIL.To = yourmail@gmail.com
log4j.appender.MAIL.layout = org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern =%d - %c -%-4r [%t] %-5p %c %x - %m %n
#数据库:JDBCAppender
log4j.appender.DATABASE = org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL = jdbc:oracle:thin:@ 210.51 . 173.94 : 1521 :YDB
log4j.appender.DATABASE.driver = oracle.jdbc.driver.OracleDriver
log4j.appender.DATABASE.user = ydbuser
log4j.appender.DATABASE.password = ydbuser
log4j.appender.DATABASE.sql = INSERT INTO A1 (TITLE3) VALUES ( ' %d - %c %-5p %c %x - %m%n' )
log4j.appender.DATABASE.layout = org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern =% d - % c -%- 4r [ % t] %- 5p % c %x - % m % n
#数据库的链接会有问题,可以重写 org.apache.log4j.jdbc.JDBCAppender 的 getConnection() 使用数
#据库链接池去得链接,可以避免 insert 一条就链接一次数据库

Test:

public class test2 {
    private static final transient Logger log = LoggerFactory.getLogger(test2.class);
    public static void main(String[] args) {    
        String name="zhangsan";
        String password = "123";
        // 构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //继承 TextConfigurationRealm,获取自定义shiro资源文件里的信息
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        //因为最终是使用Realm来验证,所以要设置Realm
        defaultSecurityManager.setRealm(iniRealm);
        // /先设置认证环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        //接下来就是登陆了,如果传入的用户名不正确,和Realm中的不匹配,那么久会异常
        AuthenticationToken token = new UsernamePasswordToken(name,password);
        try {
            subject.login(token);
            System.out.println("登陆成功");
        }catch ( AuthenticationException uae){
            System.out.println("登录失败");
        }
    }

shiro实现授权

授权在认证之后进行;

1,授权概述摆权,也叫访问控制,即在应用中控利谁能访问这些资源(如访问页面/编辑数据/页面操作等)在授权中需了解几个关健对象;主体 (subject)资源 (resource)、权限 (Permission)角色(Role).
2,关键对象介绍

1.主体

主体,即访问应用的用户,在Shiro中使用Subject代表该用户,用户只有授权后才允许访问相应的资源。
2,资源

在应用中,用户可以访问的任何东西,比如访问可JSP负面、查看/编辑某些数据、访问某个业务方法、打印文本等等部是资源,用户只要授权后才能访问。

3,权限

安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/ 删除用户数据(即很多时候部是CRUD 式权限控利)打印文裆等等,

4,角色

角色代表了操作集合,可以理解为权限的集合,一股情况下我们会赋予用户角色而不是权限,赋予权限时比较方便,典型的如:项目理理、技术总监、CTO开发工程师等都是角色,不可的角色拥有一组不同的权限。

package com.test.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.List;


/**
 * @auther:
 * @creater:
 * @time
 **/
public class test2 {
    private static final transient Logger log = LoggerFactory.getLogger(test2.class);
    public static void main(String[] args) {
        String name="zhangsan";
        String password = "123";

        // 构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //继承 TextConfigurationRealm,获取自定义shiro资源文件里的信息
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        //因为最终式使用Realm来验证,所以要设置Realm
        defaultSecurityManager.setRealm(iniRealm);
        // /先设置认证环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        //接下来就是登陆了,如果传入的用户名不正确,和Realm中的不匹配,那么久会异常
        AuthenticationToken token = new UsernamePasswordToken(name,password);
        try {
            subject.login(token);
            System.out.println("登陆成功");
        }catch ( AuthenticationException uae){
            System.out.println("登录失败");
        }
//        subject.logout();注销登录

//        判断用户是否认证通过
        boolean authenticated = subject.isAuthenticated();
        System.out.println("是否认证通过:"+authenticated);
//        角色判断
        boolean role1 = subject.hasRole("role1");
        System.out.println("是否有该角色:"+role1);
//        判断集合里面的角色,返回数组
        List<String> list = Arrays.asList("role1","role2","role3");
            boolean[] b = subject.hasRoles(list);
            for (boolean b1 : b) {
                System.out.println("是否有该角色(数组):"+b1);
        }
//        判断当前用户是否有list里的角色
        boolean b1 = subject.hasAllRoles(list);
        System.out.println("是否有所有权限"+b1);
//        权限判断
        boolean permitted = subject.isPermitted("user:update");
        System.out.println("是否有权限"+permitted);
        boolean[] permitted2 = subject.isPermitted("user:update","user:create","user:delete");
        System.out.println("是否有权限"+permitted2);
        boolean permitted3 = subject.isPermittedAll("user:update","user:create","user:delete");
        System.out.println("是否有权限"+permitted3);

    }
}

自定义Realm实现认证

shiro使用默认Realm,即配置文件ini的数据,大部分需要从系统的数据库里读取数据,所以要自定义Realm;

最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthgrizingRealm负责授权,通常自定义的realm继承AuthorizingRealn

认证只调用一次,授权调用多次(所以将查询放在认证处)

详细代码如下;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zfIw3zZp-1592219949646)(C:\Users\18035\AppData\Roaming\Typora\typora-user-images\image-20200615190600839.png)]

bean

User:(放实体类)

public class User {
    private  Integer id;
    private String username;
    private String pwd;

    public User() {
    }

    public User(Integer id, String username, String pwd) {
        this.id = id;
        this.username = username;
        this.pwd = pwd;

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }




    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", pwd='" + pwd + '\'' +

                '}';
    }
}

Activer:(放user,role,permission,为了传递参数用)

public class ActierUser {
    private User user;
    private List<String> role;
    private List<String> permission;

    public ActierUser(User user, List<String> role, List<String> permission) {
        this.user = user;
        this.role = role;
        this.permission = permission;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<String> getRole() {
        return role;
    }

    public void setRole(List<String> role) {
        this.role = role;
    }

    public List<String> getPermission() {
        return permission;
    }

    public void setPermission(List<String> permission) {
        this.permission = permission;
    }
}

service

public interface PermissionService {
    List<String> queryPerm(String name);
}
public interface RoleService {
    List<String> queryRole(String name);
}
public interface UserService {
//    查询对象
       User query(String username);
}

Impl

public class PermissionServiceImpl implements PermissionService
{
    @Override
    public List<String> queryPerm(String username) {
        List<String> list = Arrays.asList("user:create","user:update");
            return list;

    }
}
public class RoleServiceImpl implements RoleService {

    @Override
    public List<String> queryRole(String name) {
        List<String> list = Arrays.asList("role1","role2","role3");

        return list;
    }
}
public class UserServiceImpl implements UserService {
    @Override
    public User query(String name) {
       User user=null;
       switch (name)
       {
           case "zhangsan":
               user = new User(1,"zhangsan","123");
               break;
            default:
                break;
       }
            return user;
    }
}

自定义realm

package com.test.ceshi;

import com.sun.xml.internal.bind.v2.model.core.ID;
import com.test.bean.ActierUser;
import com.test.bean.User;
import com.test.service.PermissionService;
import com.test.service.RoleService;
import com.test.serviceimpl.PermissionServiceImpl;
import com.test.serviceimpl.RoleServiceImpl;
import com.test.serviceimpl.UserServiceImpl;
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.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.ArrayList;
import java.util.Collection;

/**
 * @auther:
 * @creater:
 * @time
 **/
//AuthenticatingRealm做认证的方法
    //AuthorizingRealm既可以认证也可以授权,不过要记住继承以下接口
public class UserRealm extends AuthorizingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //token.getPrincipal()从test03里里获取身份信息;AuthenticationToken:身份验证令牌
        String username = token.getPrincipal().toString();//从表头
        System.out.println(username);
        /*
        以前用户名密码一起拿到数据库进行匹配,在shiro里根据用户名把用户对象查询出来,再做密码匹配
         */
        UserServiceImpl us = new UserServiceImpl();
        RoleServiceImpl roleService = new RoleServiceImpl();
        PermissionServiceImpl permissionService = new PermissionServiceImpl();

        User user = us.query(username);
        //创建一个对象,这个对象可以放user,role,per,这样每个只查询一次就可以得到结果,将ActierUser利用PrincipalCollection获取到
        ActierUser actierUser = new ActierUser(user, roleService.queryRole(username), permissionService.queryPerm(username));
        if (user != null) {
                                                                       //第一个参数可以传任意对象   从数据库获得的密码  从数据库得到的名字
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(actierUser, user.getPwd(), user.getUsername());
            return info;
        } else {
            return null;
        }
    }
    /*
    授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ActierUser user = (ActierUser) principals.getPrimaryPrincipal();//PrincipalCollection 身份认证后得到的验证后的集合
                                                                          //这里是 ActierUser 对象;
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

		//角色
        Collection<String> roles = user.getRole();
        if (roles != null && roles.size() > 0) {
            info.addRoles(roles);

        }
         //权限
        Collection<String> permissions = user.getPermission();

        if (permissions != null && permissions.size() > 0) {
            info.addStringPermissions(permissions);
        }
//        if (user.getUser().getType()==0)超级管理员设置方法,getType()管理员种类,数据库设计表时候有
//        {
//            info.addStringPermission("*:*");
//        }
        return info;
    }
}

Test

public class test06 {
    private static final transient Logger log = LoggerFactory.getLogger(test06.class);
    public static void main(String[] args) {
        String name="zhangsan";
        String password = "123";

        // 构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //继承 TextConfigurationRealm,获取自定义shiro资源文件里的信息
        // IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        //因为最终式使用Realm来验证,所以要设置Realm
//        创建realm
        UserRealm userRealm = new UserRealm();
//        注入userRealm
        defaultSecurityManager.setRealm(userRealm);
        // /先设置认证环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        //接下来就是登陆了,如果传入的用户名不正确,和Realm中的不匹配,那么久会异常
        AuthenticationToken token = new UsernamePasswordToken(name,password);
        try {
            subject.login(token);
            System.out.println("登陆成功");
            String s = subject.getPrincipal().toString();
            System.out.println(s);

        }catch ( AuthenticationException uae){
            System.out.println("登录失败");
        }

//        subject.logout();注销登录

//        判断用户是否认证通过
        boolean authenticated = subject.isAuthenticated();
        System.out.println("是否认证通过:"+authenticated);
//        角色判断
        boolean role1 = subject.hasRole("role1");
        System.out.println("是否有该角色:"+role1);
//        判断集合里面的角色,返回数组
        List<String> list = Arrays.asList("role1","role2","role3");
        boolean[] b = subject.hasRoles(list);
        for (boolean b1 : b) {
            System.out.println("是否有该角色(数组):"+b1);
        }
//        判断当前用户是否有list里的角色
        boolean b1 = subject.hasAllRoles(list);
        System.out.println("是否有所有权限"+b1);

//        权限判断
        boolean permitted = subject.isPermitted("user:update");
        System.out.println("是否有权限"+permitted);
        boolean[] permitted2 = subject.isPermitted("user:update","user:create","user:delete");
        System.out.println("是否有权限"+permitted2);
        boolean permitted3 = subject.isPermittedAll("user:update","user:create","user:delete");
        System.out.println("是否有权限"+permitted3);

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Shiro框架可以按照以下步骤进行: 1. 了解基础概念:首先,你需要了解Shiro的基本概念和术语,例如主体(Subject)、认证(Authentication)、授权(Authorization)、Realm等。可以阅读Shiro的官方文档或者相关的教程来获得这些知识。 2. 安装和配置:安装Shiro框架并进行基本的配置。你可以在Shiro的官方网站上找到安装指南和配置示例。 3. 认证功能:学习如何使用Shiro进行用户认证,包括用户名密码认证、Remember Me功能、多Realm认证等。可以尝试编写简单的认证示例来理解这些功能。 4. 授权功能:学习如何使用Shiro进行用户授权,包括角色授权和权限授权。了解如何定义角色和权限,并且如何在代码中进行授权判断。 5. Session管理:了解Shiro如何管理用户的会话信息,包括会话超时、会话验证等。学习如何使用Shiro提供的Session API来管理会话。 6. 整合框架:如果你使用其他的Java框架,例如Spring或者Spring Boot,学习如何将Shiro与这些框架进行整合,以便更好地利用Shiro的功能。 7. 安全性优化:深入了解Shiro的安全性能优化技巧,例如密码加密、安全配置、防止常见安全漏洞等。 8. 实战练习:通过编写实际的应用程序来巩固所学的知识。可以尝试开发一个简单的Web应用程序,使用Shiro进行用户认证和授权。 除了官方文档和教程,还可以参考一些优秀的书籍或在线教程,例如《Apache Shiro官方指南》、《深入浅出Shiro安全框架》等。此外,加入Shiro的社区或者论坛,与其他开发者交流经验也是一个很好的学习方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值