参考来源
一、Shiro认识和介绍
1、什么是Shiro
Apache的强大灵活的开源安全框架
认证、授权、企业会话管理、安全加密
2、Shiro与Spring Security比较
Shiro | Spring Security |
---|---|
简单、灵活 | 复杂、笨重 |
可脱离Spring | 不可脱离Spring |
粒度较粗 | 粒度更细 |
3、Shiro整体架构
[图片上传失败...(image-d9c4de-1568169456216)]
二、Shiro认证授权过程
1、Shiro认证过程
graph LR
A(创建SecurityManager) -->B(主体提交认证)
B --> C(SecurityManager认证)
C --> D(Authenticator认证)
D --> E(Realm认证)
代码:
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser(){
simpleAccountRealm.addAccount("admin","admin123","admin","user");
}
@Test
public void testAuthentication(){
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);
//获取主体
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
//主体提交认证
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "admin123");
subject.login(usernamePasswordToken);
System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
subject.logout();
System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
}
2、Shiro授权过程
graph LR
A(创建SecurityManager) -->B(主体授权)
B --> C(SecurityManager授权)
C --> D(Authorizer授权)
D --> E(Realm获取角色权限数据)
代码:
subject.login(usernamePasswordToken);
System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
subject.checkRole("admin");
subject.checkRoles("admin","user");
三、Shiro的Realm
1、Shiro的iniRealm使用
在Test Resources中添加文件user.ini,在里面添加用户信息
[users]
Admin=admin123,admin
Tom=tom123,system
[roles]
admin=user:delete
system=user:update
代码
@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 usernamePasswordToken = new UsernamePasswordToken("Tom", "tom123");
subject.login(usernamePasswordToken);
System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
subject.checkRole("system");
subject.checkPermission("user:update");
}
2、Shiro的JdbcRealm使用
代码:
DruidDataSource datasource = new DruidDataSource();
{
datasource.setUrl("jdbc:mysql://192.168.243.20:9097/user_role");
datasource.setUsername("root");
datasource.setPassword("b#12345678");
}
@Test
public void testAuthentication(){
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setDataSource(datasource);
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(jdbcRealm);
//获取主体
...
}
因为JdbcRealm中会默认查询
DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
所以在对应的库中添加users表,并带有相应字段和数据,则可查询成功
需要使用自定义的查询表时,可使用自定义的查询sql语句
String authSql = "select phone from aur_member where member_name = ?";
jdbcRealm.setAuthenticationQuery(authSql);
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("tim1", "13751836453");
3、Shiro自定义Realm
继承AuthorizingRealm类,doGetAuthorizationInfo是授权,doGetAuthenticationInfo是认证
public class CustomRealm extends AuthorizingRealm {
Map<String,String> userMap = new HashMap<>();
{
userMap.put("admin","admin123");
super.setName("customRealm");
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String userName = (String) principalCollection.getPrimaryPrincipal();
//从数据库或者缓存中获取角色数据
Set<String> roles = getRolesByUserName(userName);
Set<String> permissions = getPermissionByUserName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo;
}
private Set<String> getPermissionByUserName(String userName) {
Set<String> sets = new HashSet<>();
sets.add("user:delete");
sets.add("user:add");
sets.add("user:select");
return sets;
}
private Set<String> getRolesByUserName(String userName) {
Set<String> sets = new HashSet<>();
sets.add("admin");
sets.add("system");
return sets;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1、从主体传过来的认证信息中,获取用户名
String userName = (String) authenticationToken.getPrincipal();
//2、通过用户名到数据库中获取凭证
String password = getPasswordByUserName(userName);
if (password == null){
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("admin",password,"customRealm");
return authenticationInfo;
}
// 模拟数据库
private String getPasswordByUserName(String userName) {
return userMap.get(userName);
}
}
创建单元测试类
@Test
public void testAuthentication(){
CustomRealm customRealm = new CustomRealm();
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(customRealm);
//获取主体
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
//主体提交认证
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "admin123");
subject.login(usernamePasswordToken);
System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
subject.checkRole("admin");
subject.checkPermissions("user:delete","user:select");
}
四、Shiro加密
1、HashedCredentialsMatcher
在CustomRealmTest的testAuthentication方法中添加上
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//加密的算法
matcher.setHashAlgorithmName("md5");
//加密的次数
matcher.setHashIterations(1);
customRealm.setCredentialsMatcher(matcher);
在数据库中保存的密码就需要MD5加密后的结果
public static void main(String[] args) {
Md5Hash md5Hash = new Md5Hash("admin123");
System.out.println(md5Hash.toString());
}
2、自定义Realm中使用散列
3、盐的使用
使用盐后的MD5值,将该值保存到数据库的表密码中
public static void main(String[] args) {
Md5Hash md5Hash = new Md5Hash("admin123","admin");
System.out.println(md5Hash.toString());
}
在CustomRealm的doGetAuthenticationInfo方法中添加上
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("admin"));
网友评论