转载请注明出处:
牵手生活--:笔记是整理思路方式,分享是一个美德,牵手是我的生活方式
shiro概述参见shiro(java安全框架)
shiro(java安全框架)
认识shiro需要理解的内容
在idea中创建一个maven javaweb工程HelloShiro
配置pom.xml文件引入shiro核心包和junit
org.apache.shiro
shiro-core
1.4.0
junit
junit
3.8.1
junit
junit
4.0
shiro认证
创建一个单元测试类(junit)AuthenticationTest.java,并测试
模拟认证请求的过程
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授权
修改单元测试,并查看结果
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
[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文件中
}
}
JdbcRealm讲解
在pom.xml中添加对mysql 和数据源druid的引入
mysql
mysql-connector-java
6.0.6
com.alibaba
druid
1.1.6
在mysql数据库中创建对应的表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的源码发现里面有默认的查询语句
所以我们应该根据默认的语句创建几张对应的表users、user_roles、roles_permissions、user_roles
idea配置database连接mysql
其他配置如:
创建test_user表,并添加数据
创建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 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 roles = getRolesByUserName(userName);
//从数据库或缓冲中获得权限数据
Set permissions = getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(permissions);
simpleAuthorizationInfo.setRoles(roles);
return simpleAuthorizationInfo;
}
/**
* 模拟用户权限数据
* @param userName
* @return
*/
private Set getPermissionsByUserName(String userName) {
Set sets = new HashSet<>();
sets.add("user:myAdd");
sets.add("user:delete");
sets.add("user:update");
return sets;
}
/**
* 模拟角色数据
* @param userName
* @return
*/
private Set getRolesByUserName(String userName) {
Set 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中使用散列
- 盐的使用(加盐处理)
如果有加盐处理还需要添加盐的处理
自定义realm的加密&加盐CustomRealmJM.java
public class CustomRealmJM extends AuthorizingRealm {
/*模拟用户的数据库信息*/
Map 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 roles = getRolesByUserName(userName);
//从数据库或缓冲中获得权限数据
Set permissions = getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(permissions);
simpleAuthorizationInfo.setRoles(roles);
return simpleAuthorizationInfo;
}
/**
* 模拟用户权限数据
* @param userName
* @return
*/
private Set getPermissionsByUserName(String userName) {
Set sets = new HashSet<>();
sets.add("user:myAdd");
sets.add("user:delete");
sets.add("user:update");
return sets;
}
/**
* 模拟角色数据
* @param userName
* @return
*/
private Set getRolesByUserName(String userName) {
Set 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加强篇