1 说明

1.1 Realm的作用

Realm和认证和授权时的数据交互有关,相当于DAO层。

1.2 AuthorizingRealm

》层次关系图

》作用
继承AuthorizingRealm类后重写doGetAuthorizationInfo和doGetAuthenticationInfo就可以实现授权和认证逻辑。

2 代码实现

2.1 创建一个maven项目并引入shiro、junit依赖

2.2 创建一个类继承AuthorizingRealm

2.3 重写doGetAuthorizationInfo和doGetAuthenticationInfo

2.4 完整代码

package com.xunyji.demo04.realm;

import com.xunyji.demo0.StringUtilsXyj;
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.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set; /**
* @author AltEnter
* @create 2019-01-23 20:32
* @desc 自定义Realm,md
**/
public class CustomRealm extends AuthorizingRealm { private Logger log = LoggerFactory.getLogger(this.getClass()); private Map<String, String> userMap = new HashMap<String, String>(); {
getName();
// userMap.put("fury", "111111");
// userMap.put("fury", "96e79218965eb72c92a549dd5a330112");
userMap.put("fury", "66b747dd6c7c7c8ca4227a67fff8ea6e");
} /**
* 授权逻辑
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 01 获取用户名
String username = (String) principals.getPrimaryPrincipal();
// 02 获取权限集合
Set<String> permissionSet = getPermissionSetByUsername(username);
// 03 获取角色集合
Set<String> roleSet = getRoleSetByUsername(username);
// 04 封装SimpleAuthorizationInfo对象
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roleSet);
simpleAuthorizationInfo.setStringPermissions(permissionSet);
return simpleAuthorizationInfo;
} /**
* 根据用户名获取权限集合
* @param username
* @return
*/
private Set<String> getPermissionSetByUsername(String username) {
HashSet<String> permissionSet = new HashSet<>();
permissionSet.add("user:create");
permissionSet.add("user:delete");
permissionSet.add("user:update");
return permissionSet;
} /**
* 根据用户名获取角色集合
* @param username
* @return
*/
private Set<String> getRoleSetByUsername(String username) {
HashSet<String> roleSet = new HashSet<>();
roleSet.add("admin");
roleSet.add("user");
return roleSet;
} /**
* 认证逻辑
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 01 获取前端用户名和密码
String username = (String) token.getPrincipal();
String passoword = new String((char[]) token.getCredentials());
if (StringUtilsXyj.isEmpty(passoword) || StringUtilsXyj.isEmpty(username)) {
String msg = "doGetAuthenticationInfo - 用户名和密码不能为空";
log.info(msg);
throw new RuntimeException(msg);
}
log.info(String.format("doGetAuthenticationInfo - 前端传过来的用户信息为 - 用户名为:%s ,用户密码为:%s", username, passoword));
System.out.println(String.format("doGetAuthenticationInfo - 前端传过来的用户信息为 - 用户名为:%s ,用户密码为:%s", username, passoword)); // 02 根据用户名获取用户密码
String pwd = getPasswordByUsername(username);
// 03 前端密码加密加盐处理
passoword = string2Md5Hash(passoword, "AltEnter");
System.out.println("加盐加密后的密码为:" + pwd); // 04 密码比对
if (passoword.equals(pwd)) {
// 封装SimpleAuthenticationInfo对象
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, passoword, getName());
// 加盐处理
simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("AltEnter"));
return simpleAuthenticationInfo;
} else {
String msg = "doGetAuthenticationInfo - 用户名或者密码错误";
log.info(msg);
System.out.println(msg);
throw new RuntimeException(msg);
}
} /**
* 密码加密加盐处理
* @param password 待加密密码
* @param salt 盐
* @return 经过加密和加盐处理后的密码
*/
private String string2Md5Hash(String password, String salt) {
return new Md5Hash(password, salt).toString();
} /**
* 根据用户名获取密码
* @param username
* @return
*/
private String getPasswordByUsername(String username) {
String pwd = userMap.get(username);
return pwd;
} public static void main(String[] args) {
// Md5Hash md5Hash = new Md5Hash("111111");
// System.out.println("111111加密后的结果为:" + md5Hash.toString());
// 96e79218965eb72c92a549dd5a330112 Md5Hash md5Hash = new Md5Hash("111111", "AltEnter");
System.out.println("111111经过MD5加密和AltEnter加盐后的结果为:" + md5Hash.toString());
// 66b747dd6c7c7c8ca4227a67fff8ea6e
}
}

3 测试类

package com.xunyji.demo04.realm;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test; import static org.junit.Assert.*; public class CustomRealmTest {
@Test
public void test01() {
CustomRealm customRealm = new CustomRealm();
// shiro加密 start
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//选择加密方式
matcher.setHashAlgorithmName("md5");
//加密次数
matcher.setHashIterations(1);
// 给自定义Realm设置加密规则
customRealm.setCredentialsMatcher(matcher);
// shiro加密 end // 更改认证策略 start
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
FirstSuccessfulStrategy firstSuccessfulStrategy = new FirstSuccessfulStrategy();
ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
modularRealmAuthenticator.setAuthenticationStrategy(firstSuccessfulStrategy);
defaultSecurityManager.setAuthenticator(modularRealmAuthenticator);
// 更改认证策略 end defaultSecurityManager.setRealm(customRealm); SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111"); subject.login(token);
System.out.println(String.format("认证信息为:%s", subject.isAuthenticated())); System.out.println(String.format("拥有admin角色吗? - %s", subject.hasRole("admin")));
System.out.println(String.format("拥有user:create权限吗? - %s", subject.isPermitted("user:create"))); subject.logout();
System.out.println(String.format("认证信息为:%s", subject.isAuthenticated())); }
}

4 注意

4.1 可以给SecurityManager设置认证策略

4.2 可以给Realm设置MD5加密

4.3 SecurityManager必须先设置认证策略再设置Realm

Shrio04 自定义Realm的更多相关文章

  1. 权限框架 - shiro 自定义realm

    上篇文章中是使用的默认realm来实现的简单登录,这仅仅只是个demo,真正项目中使用肯定是需要连接数据库的 首先创建自定义realm文件,如下: 在shiro中注入自定义realm的完全限定类名: ...

  2. Shrio认证详解+自定义Realm

    Authentication(身份认证)是Shiro权限控制的第一步,用来告诉系统你就是你. 在提交认证的时候,我们需要给系统提交两个信息: Principals:是一个表示用户的唯一属性,可以是用户 ...

  3. Shiro第二篇【介绍Shiro、认证流程、自定义realm、自定义realm支持md5】

    什么是Shiro shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证.用户授权. spring中有spring security (原名Acegi),是一个权限框架,它和sp ...

  4. shiro(二)自定义realm,模拟数据库查询验证

    自定义一个realm类,实现realm接口 package com; import org.apache.shiro.authc.*; import org.apache.shiro.realm.Re ...

  5. shiro自定义Realm

    1.1 自定义Realm 上边的程序使用的是shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm. ...

  6. Shiro入门 - 通过自定义Realm连数数据库进行授权

    shiro-realm.ini [main] #自定义Realm myRealm=test.shiro.MyRealm #将myRealm设置到securityManager,相当于Spring中的注 ...

  7. Shiro入门 - 通过自定义Realm连数数据库进行认证(md5+salt形式)

    shiro-realm-md5.ini [main] #定义凭证匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCrede ...

  8. Shiro入门 - 通过自定义Realm连数数据库进行认证

    添加shiro-realm.ini文件 [main] #自定义Realm myRealm=test.shiro.MyRealm #将myRealm设置到securityManager,相当于Sprin ...

  9. shiro教程2(自定义Realm)

    通过shiro教程1我们发现仅仅将数据源信息定义在ini文件中与我们实际开发环境有很大不兼容,所以我们希望能够自定义Realm. 自定义Realm的实现 创建自定义Realmjava类 创建一个jav ...

随机推荐

  1. Winform开发常用控件之ComboBox、ListBox

    ComboBox就是我们常见的下拉框,对于此类控件,我们最关心的当然是数据的绑定和选择值得获取. 首先介绍个属性DropDownStyle,如果不允许ComboBox输入值,只能选择,就选DropDo ...

  2. 2018-2019-2 《网络对抗技术》Exp1 PC平台逆向破解 20165222

    Exp1 PC平台逆向破解 1,掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码 NOP:空指令,作用就是直接跳到下一指令.机器码为:90. JNE:判断0标志位,不等于0跳转.机器码 ...

  3. C语言 scanf()和gets()函数的区别

    C语言 scanf()和gets()函数的区别 1.相同点:scanf( )函数和gets( )函数都可用于输入字符串 2.不同点:两者在功能上有所区别,具体区别如下: 要实现如下需求“从控制台输入字 ...

  4. 获取 graphql schema 信息

    模块 npm install -g get-graphql-schema get-graphql-schema GRAPHQL_URL > schema.graphql 简单使用 使用prism ...

  5. HDU1735 字数统计

    版权声明:长风原创 https://blog.csdn.net/u012846486/article/details/28011667 字数统计 Time Limit: 1000/2000 MS (J ...

  6. Linux 解压zip need PK compat. v4.5 (can do v2.1)

    p7z 当使用7zip压缩大于4G的文件后,在linux下解压时,出现下面的提示,无法解压: [root@localhost root]# unzip Wrestlemania20.zip Archi ...

  7. Log4j(3)--rootLogger根配置和appender输出类型配置

    参考博客:http://blog.java1234.com/blog/articles/270.html 一.rootLogger根配置: Log4j 根配置语法 log4j.rootLogger = ...

  8. [html][javascript] Cookie

    更多可参考:http://www.cnblogs.com/newsouls/archive/2012/11/12/2766567.html // 读 cookie 方法 function getCoo ...

  9. 5月31日上课笔记-Mysql简介

    一.mysql 配置mysql环境变量 path中添加 D:\Program Files\MySQL\MySQL Server 5.7\bin cmd命令: 登录:mysql -uroot -p 退出 ...

  10. C# mysql 连接Apache Doris

    前提:  安装mysql odbc驱动程序,目前只不支持8.0的最新版本驱动,个人使用的是5.1.12的驱动(不支持5.2以上版本),下载地址为: x64: https://cdn.mysql.com ...