Shiro入门

导读:本篇文章讲解 Shiro入门,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、概述

1.1 什么是Shiro

Apache Shiro是一个功能强大、简单易用的Java安全框架,提供了认证、授权、加密和会话管理等功能。

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

(1)认证
用户身份识别,常被称为用户“登录”,判断用户是否登陆,如果未登陆则拦截其请求。

(2)授权
访问控制;当用户登陆后,判断其身份是否有权限访问相应的资源,如果没有权限则拦截。

1.2 Shiro框架组成

在这里插入图片描述

Subject:主体,可以是任意对象。在Web应用中,一般使用当前登录用户作为主体。如果主体要访问系统,那么Shiro就会对主体进行认证、授权等工作。

SecurityManager:执行了主体的认证、授权工作、会话管理、缓存管理等工作。

Authenticator:负责执行认证操作。

Authorizer:负责执行授权操作。

SessionManager:负责对session进行管理;

Session DAO: 负责管理session数据。一般来说,如果需要针对个性化的Session数据存储,才需要使用Session DAO;

CacheManager:负责对Session和授权数据进行缓存;

Realm:相当于数据源,通过该Realm存取认证、授权相关的数据;

1.3 过滤器

Shiro是以过滤器的方式对访问规则进行控制,并内置一组过滤器。其中比较常用的是:
anon:不认证也可以访问;
authc:必须认证后才允许访问;
perms:指定资源需要有指定权限才允许访问;

二,Shiro认证

第一步:构建SecurityManager环境

//构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置数据源
        defaultSecurityManager.setRealm(simpleAccountRealm);

第二步: 主体提交认证请求

//主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();

登录测试举例:

package com.lmc.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAccount;
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;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 17:27 2019/10/27
 */
public class ShiroTest {
    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before
    public void addUser(){
        simpleAccountRealm.addAccount("lmc", "111");
    }

    @Test
    public void testAuthentication(){
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //设置数据源
        defaultSecurityManager.setRealm(simpleAccountRealm);
        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
        //登录
        subject.login(token);

        //获取登录名
        System.out.println(subject.getPrincipal());
        System.out.println("isAuthenticated : " + subject.isAuthenticated());

        //注销
        subject.logout();
        System.out.println("isAuthenticated : " + subject.isAuthenticated());
    }


}

二,Shiro授权

  • 创建SecurityManager
  • 进行主体授权
  • 主体授权交给SecurityManager授权
  • Authorizer授权
  • Realm获取角色权限数据

测试举例:

package com.lmc.test;

import com.lmc.beans.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAccount;
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;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 17:27 2019/10/27
 */
public class ShiroTest {
    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before
    public void addUser(){
        //给角色授权(一个或多个)
        //simpleAccountRealm.addAccount("lmc", "111", "admin");
        simpleAccountRealm.addAccount("lmc", "111", "admin", "user");
    }

    @Test
    public void testAuthentication(){
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //设置数据源
        defaultSecurityManager.setRealm(simpleAccountRealm);
        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
        //登录
        subject.login(token);

        System.out.println("isAuthenticated : " + subject.isAuthenticated());
        //检查用户是否具有admin权限(一个或多个)
        //subject.checkRole("admin");
        subject.checkRoles("admin", "user");
 
    }


}

三, Realm

3.1 iniRealm

测试资源文件 user.ini:

[users]
lmc=111,admin
[roles]
admin=user:delete,user:update

测试举例:

package com.lmc.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.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 18:05 2019/10/27
 */
public class InitRealmTest {


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

        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
        //登录
        subject.login(token);

        System.out.println("isAuthenticated : " + subject.isAuthenticated());
        //获取登录名
        System.out.println(subject.getPrincipal());
		//检查是否有该角色
        subject.checkRole("admin");
        //检查是否有该权限
        subject.checkPermission("user:update");

    }


}

3.2 jdbcRealm

第一步: 导入相关依赖

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

第二步: 创建数据源

    DruidDataSource dataSource = new DruidDataSource();

    {
        dataSource.setUrl("jdbc:mysql://localhost:3306/mblog?serverTimezone=GMT%2B8");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
    }


测试举例:

package com.lmc.test;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 18:20 2019/10/27
 */
public class JdbcRealmTest {
    DruidDataSource dataSource = new DruidDataSource();

    {
        dataSource.setUrl("jdbc:mysql://localhost:3306/mblog?serverTimezone=GMT%2B8");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
    }

    @Test
    public void testAuthentication() {
        //创建jdbcRealm对象
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);
        //使用自定义SQL语句
        String sql = "select password from user where username = ?";
        jdbcRealm.setAuthenticationQuery(sql);
        //权限开关,默认为false
        jdbcRealm.setPermissionsLookupEnabled(true);
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);

        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
        //登录
        subject.login(token);

        System.out.println("isAuthenticated : " + subject.isAuthenticated());
        //获取登录名
        System.out.println(subject.getPrincipal());

        subject.checkRoles("admin", "user");
        subject.checkPermission("user:delete");

    }


}

注意:

  • 默认情况下jdbcrealm不会开启权限,要自己手动开启
//权限开关,默认为false
        jdbcRealm.setPermissionsLookupEnabled(true);
  • 默认情况下数据库需要有users, user_roles, roles_permissions表, 如果要自定义表,可以自己修改:
		JdbcRealm jdbcRealm = new JdbcRealm();
//使用自定义SQL语句
        String sql = "select password from user where username = ?";
        jdbcRealm.setAuthenticationQuery(sql);

3.3 自定义Realm

第一步: 定义一个自定义Realm, 继承 AuthorizingRealm

package com.lmc.shiro.realm;

import com.lmc.shiro.beans.User;
import com.lmc.shiro.service.UserService;
import org.apache.shiro.authc.*;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 11:46 2019/10/27
 */
@Component("userRealm")
public class UserRealm extends AuthorizingRealm {
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        
        return null  ;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { 
        return null;
    }

}

第二步: 认证, 重写 AuthenticationInfo 方法

/**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.得到令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //2.调用业务组件进行登录判断
        User user = new User();
        user.setUsername(token.getUsername());
//        user.setPassword(new String(token.getPassword()));
        System.out.println("lmchh = " + token.getUsername());
        UserService userService = new UserService();
        List<User> users = userService.find((String) authenticationToken.getPrincipal());
        //3.判断用户是否为空,如果不为空代表登录成功
        if (users != null) {
		/*
		 	参数1:主角(用户对象)
		 	参数2:密码
		 	参数3:realm的类名
		 */
            user = users.get(0);
            return new SimpleAuthenticationInfo(user, user.getPassword(), user.getUsername());
        }
        return null;
    }

第三步: 授权, 重写 doGetAuthorizationInfo 方法

/**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User) principalCollection.getPrimaryPrincipal();
        //模拟从数据库或缓存中获取角色数据
        Set<String> roles = getRolesByUsername(user.getUsername());
        //模拟从数据库或缓存中获取权限数据
        Set<String> permissions = getPermissionsByUsername(user.getUsername());
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permissions);
        return simpleAuthorizationInfo  ;
    }

源文件:

package com.lmc.shiro.realm;

import com.lmc.shiro.beans.User;
import com.lmc.shiro.service.UserService;
import org.apache.shiro.authc.*;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 11:46 2019/10/27
 */
@Component("userRealm")
public class UserRealm extends AuthorizingRealm {
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User) principalCollection.getPrimaryPrincipal();
        //模拟从数据库或缓存中获取角色数据
        Set<String> roles = getRolesByUsername(user.getUsername());
        //模拟从数据库或缓存中获取权限数据
        Set<String> permissions = getPermissionsByUsername(user.getUsername());
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permissions);
        return simpleAuthorizationInfo  ;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.得到令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //2.调用业务组件进行登录判断
        User user = new User();
        user.setUsername(token.getUsername());
//        user.setPassword(new String(token.getPassword()));
        System.out.println("lmchh = " + token.getUsername());
        UserService userService = new UserService();
        List<User> users = userService.find((String) authenticationToken.getPrincipal());
        //3.判断用户是否为空,如果不为空代表登录成功
        if (users != null) {
		/*
		 	参数1:主角(用户对象)
		 	参数2:密码
		 	参数3:realm的类名
		 */
            user = users.get(0);
            return new SimpleAuthenticationInfo(user, user.getPassword(), user.getUsername());
        }
        return null;
    }

    private Set<String> getPermissionsByUsername(String username) {
        Set<String> sets = new HashSet<>();
        sets.add("user:select");
        sets.add("user:update");
        return sets;
    }

    private Set<String> getRolesByUsername(String username) {
        Set<String> sets = new HashSet<>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }

}

第三步: 编写测试类

package com.lmc.test;

import com.lmc.shiro.realm.UserRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

/**
 * @Author lmc
 * @Description
 * @Date: Create in 21:28 2019/10/27
 */
public class UserRealmTest {

    @Test
    public void testAuthentication() {
        UserRealm userRealm = new UserRealm();
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(userRealm);

        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("lmc", "111");
        //登录
        subject.login(token);

        System.out.println("isAuthenticated : " + subject.isAuthenticated());
        //获取登录名
        System.out.println(subject.getPrincipal());

        subject.checkRole("admin");
        subject.checkPermission("user:update");
    }

}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81657.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!