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. 同时发出 ajax 拿到正确的返回值问题

    方案 大概意思就是前端在data里面 传一个标示给后台,  后台再ajax返回的时候携带这个标示

  2. 三十分钟理解:双调排序Bitonic Sort,适合并行计算的排序算法

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入 双调排序是data-indepen ...

  3. ZetCode PyQt4 tutorial First programs

    #!/usr/bin/python # -*- coding: utf-8 -*- """ ZetCode PyQt4 tutorial In this example, ...

  4. java面试题8

    java面试题08 1.short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? short s1 = 1; s1 = s1 + 1;编译 ...

  5. .Net调用Java端带有WS-Security支持的Web Service各方案实战【转】

    原文:http://www.xuebuyuan.com/641669.html 到现在为止,我们AEP平台已经发布很长一段时间了,也有很多ISV接入并上线了,就语言而言,目前主要有三类:Java..N ...

  6. 【idea】idea的常规设置

    [一]在输入框输入字符,自动提示代码 File->Power Save Mode  去掉“对号” [二]自动代码提示的快捷键设置 (1)不区分大小写提示 (2)修改快捷提示快捷键.将basic= ...

  7. flow 类型生成工具 flow-typed 简单使用

    flow 是一个javascript 的静态检查工具,flow-typed 为我们提供了三方类似type 的生成 安装flow-typed 使用全局安装 yarn global add flow-ty ...

  8. CSS为英文和中文字体分别设置不同的字体

    font-family的调用方法: div { font-family:Arial,'Times New Roman','Microsoft YaHei',SimHei; font:bold 12px ...

  9. 如何重启 Windows 10 子系统(WSL) ubuntu

    如何重启 Windows 10 子系统(WSL) ubuntu WSL 子系统是基于 LxssManager 服务运行的. 只需要将 LxssManager 重启即可. 可以做成一个 bat 文件. ...

  10. mysql索引优化续

    (1)索引类型: Btree索引:抽象的可以理解为“排好序的”快速查找结构myisam,innodb中默认使用Btree索引 hash索引:hash索引计算速度非常的快,但数据是随机放置的,无法对范围 ...