记录我学习安全框架Shiro的一些笔记。
Shiro VS Spring Security
Apache Shiro
简单灵活,可脱离Spring,粒度较粗;可以自己拓展,适合通过资源进行权限控制;
Spring Security
复杂笨重,不可脱离Spring,力度更细;适合做数据权限控制;
Shiro的认证过程
- 创建Security Manager
- 主体提交认证
- Security Manager认证
- Authenticator认证
- Realm认证
代码如下:
java代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.leezy.shiro.shirotest;
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("LEEZY", "123456"); } @Test public void testAuthentication() { DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("LEEZY", "123456"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.isAuthenticated(); subject.logout(); System.out.println("isAuthenticated: " + subject.isAuthenticated()); } }
|
pom文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.leezy.shiro</groupId> <artifactId>shirotest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging>
<name>shirotest</name> <url>http://maven.apache.org</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
<dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>RELEASE</version> </dependency> </dependencies>/. </project>
|
Shiro授权
- 创建 Security Manager
- 主体授权
- Security Manager 授权
- Authorizer认证
- Realm 获取角色权限数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.leezy.shiro.shirotest;
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("LEEZY", "123456", "admin", "user"); } @Test public void testAuthentication() { DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("LEEZY", "123456"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.isAuthenticated(); subject.checkRoles("admin", "user"); } }
|
InitRealm的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.leezy.shiro.shirotest;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.subject.Subject; import org.junit.Test;
public class InitRealmTest {
@Test public void testAuthentication() { IniRealm iniRealm = new IniRealm("classpath:user.ini"); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(iniRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("LEEZY", "123456"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); subject.checkPermission("user:update"); } }
|
user.ini
1 2 3 4
| [users] LEEZY=123456,admin [roles] admin=user:delete,user:update
|
JDBCRealm的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.leezy.shiro.shirotest;
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;
import com.alibaba.druid.pool.DruidDataSource;
public class JdbcRealmTest { DruidDataSource dataSource = new DruidDataSource(); { dataSource.setUrl("jdbc:mysql://192.168.56.101:3306/test"); dataSource.setUsername("root"); dataSource.setPassword("Zdh!123456"); } @Test public void testAuthentication() { JdbcRealm jdbcRealm = new JdbcRealm(); jdbcRealm.setDataSource(dataSource); jdbcRealm.setPermissionsLookupEnabled(true); String select_sql = "select password from test_user where username = ?"; jdbcRealm.setAuthenticationQuery(select_sql); String role_sql = "select role_name from test_user_role where user_name = ?"; jdbcRealm.setUserRolesQuery(role_sql); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(jdbcRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("SAKURA", "123456"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:select"); } }
|
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.14</version> </dependency>
|
查看JdbcRealm源码可以发现,它有默认的SQL查询语句,只要建立相应的数据表就可以。
自定义Realm
自定义Realm继承AuthorizingRealm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| package com.leezy.shiro.realm;
import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;
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;
public class CustomRealm extends AuthorizingRealm{ Map<String, String> userMap = new HashMap<String, String>(16); { userMap.put("LEEZY", "123456"); super.setName("CustomRealm"); } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); Set<String> roles = getRolesByUserName(username); Set<String> permissions = getPermissionsByUserName(username); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); String password = getPasswordByUserName(username); if(password == null) { return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("LEEZY", password, "CustomRealm"); return authenticationInfo; } private Set<String> getPermissionsByUserName(String username) { Set<String> sets = new HashSet<String>(); sets.add("user:delete"); sets.add("user:add"); return sets; } public Set<String> getRolesByUserName(String username) { Set<String> sets = new HashSet<String>(); sets.add("admin"); sets.add("user"); return sets; } private String getPasswordByUserName(String username) { return userMap.get(username); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.leezy.shiro.shirotest;
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;
import com.leezy.shiro.realm.CustomRealm;
public class CustomRealmTest {
@Test public void testAuthentication() { CustomRealm customRealm = new CustomRealm(); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(customRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("LEEZY", "123456"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); subject.checkPermission("user:add"); } }
|
Shiro加密
Shiro加密方式:
- HashedCredentialsMatcher
- 自定义Realm中使用散列
- 盐的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| package com.leezy.shiro.realm;
import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;
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;
public class CustomRealm extends AuthorizingRealm{ Map<String, String> userMap = new HashMap<String, String>(16); { userMap.put("LEEZY", "e43a7da8514a1c9d566164b3ea731a4a"); super.setName("CustomRealm"); } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); Set<String> roles = getRolesByUserName(username); Set<String> permissions = getPermissionsByUserName(username); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); String password = getPasswordByUserName(username); if(password == null) { return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("LEEZY", password, "CustomRealm"); authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("SAKURA")); return authenticationInfo; } private Set<String> getPermissionsByUserName(String username) { Set<String> sets = new HashSet<String>(); sets.add("user:delete"); sets.add("user:add"); return sets; } public Set<String> getRolesByUserName(String username) { Set<String> sets = new HashSet<String>(); sets.add("admin"); sets.add("user"); return sets; } private String getPasswordByUserName(String username) { return userMap.get(username); } public static void main(String[] args) { Md5Hash md5Hash = new Md5Hash("123456", "SAKURA"); System.out.println(md5Hash.toString()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.leezy.shiro.shirotest;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; import org.junit.Test;
import com.leezy.shiro.realm.CustomRealm;
public class CustomRealmTest {
@Test public void testAuthentication() { CustomRealm customRealm = new CustomRealm(); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(customRealm); HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("md5"); matcher.setHashIterations(1); customRealm.setCredentialsMatcher(matcher); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("LEEZY", "123456"); subject.login(token); System.out.println("isAuthenticated: " + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); subject.checkPermission("user:add"); } }
|
Shiro集成Spring
// TODO