Shrio00 Shiro认证登录、权限管理环境搭建
基础环境准备:
JDK -> java version "1.8.0_101"
MAVEN -> Apache Maven 3.5.0
1 导入依赖
mysql驱动
mybatis
shiro相关
<!--shiro相关--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.20</version> </dependency>
<?xml version="1.0" encoding="UTF-8"?> <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>cn.xiangxu</groupId> <artifactId>apache_shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>apache_shiro</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--<dependency>--> <!--<groupId>org.springframework.boot</groupId>--> <!--<artifactId>spring-boot-starter-tomcat</artifactId>--> <!--<scope>provided</scope>--> <!--</dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--shiro相关--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.20</version> </dependency> <!--工具相关--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!--jsp相关--> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <!--servlet相关--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> <!--jstl相关--> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2 springboot项目整合mybatis
2.1 全局配置
spring: datasource: # 数据源配置 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver username: root password: 182838 url: jdbc:mysql://127.0.0.1/auth?characterEncoding=utf-8&useSSL=false mvc: # JSP页面配置 springboot项目会自动到main下的webapp下去寻找jsp文件 view: prefix: /pages/ suffix: .jsp mybatis: # mybatis配置 mapper-locations: mappers/*.xml # xml文件位置 放在resources目录下 type-aliases-package: cn.xiangxu.apache_shiro.model # xml文件用到的模型位置
2.2 创建数据库相关表
用户表、角色表、权限表、用户角色表、权限角色表
-- 权限表 CREATE TABLE permission ( pid INT (11) NOT NULL AUTO_INCREMENT, pname VARCHAR (255) NOT NULL DEFAULT '', purl VARCHAR (255) DEFAULT '', PRIMARY KEY (pid) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; INSERT INTO permission VALUES ('1', 'add', ''); INSERT INTO permission VALUES ('2', 'delete', ''); INSERT INTO permission VALUES ('3', 'edit', ''); INSERT INTO permission VALUES ('4', 'query', ''); -- 用户表 CREATE TABLE user ( uid INT (11) NOT NULL AUTO_INCREMENT, username VARCHAR (255) NOT NULL DEFAULT '', password VARCHAR (255) NOT NULL DEFAULT '', PRIMARY KEY (uid) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; INSERT INTO user VALUES ('1', 'admin', '123'); INSERT INTO user VALUES ('2', 'demo', '123'); -- 角色表 CREATE TABLE role ( rid INT (11) NOT NULL AUTO_INCREMENT, rname VARCHAR (255) NOT NULL DEFAULT '', PRIMARY KEY (rid) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; INSERT INTO role VALUES ('1', 'admin'); INSERT INTO role VALUES ('2', 'customer'); -- 权限角色关系表 CREATE TABLE permission_role ( rid INT (11) NOT NULL , pid INT (11) NOT NULL , KEY idx_pid(pid), KEY idx_rid(rid) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; INSERT INTO permission_role VALUES (1, 1); INSERT INTO permission_role VALUES (1, 2); INSERT INTO permission_role VALUES (1, 3); INSERT INTO permission_role VALUES (1, 4); INSERT INTO permission_role VALUES (2, 1); INSERT INTO permission_role VALUES (2, 4); -- 用户角色关系表 CREATE TABLE user_role ( uid INT (11) NOT NULL , rid INT (11) NOT NULL , KEY idx_uid(uid), KEY idx_rid(rid) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; INSERT INTO user_role VALUES (1, 1); INSERT INTO user_role VALUES (2, 2);
2.3 编写实体类
用户类、角色类、权限类
package cn.xiangxu.apache_shiro.model; import lombok.Data; import java.util.HashSet; import java.util.Set; @Data public class User { private Integer uid; private String username; private String password; private Set<Role> roleSet = new HashSet<>(); }
package cn.xiangxu.apache_shiro.model; import lombok.Data; import java.util.HashSet; import java.util.Set; @Data public class Role { private Integer rid; private String rname; private Set<User> userSet = new HashSet<>(); private Set<Permission> permissionSet = new HashSet<>(); }
package cn.xiangxu.apache_shiro.model; import lombok.Data; @Data public class Permission { private Integer pid; private String pname; private String purl; public Permission() { } }
2.3 编写mapper接口
package cn.xiangxu.apache_shiro.mapper; import cn.xiangxu.apache_shiro.model.User; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; /** * User持久层接口 */ @Repository public interface UserMapper { User findByUsername(@Param("username") String username); }
2.4 编写mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.xiangxu.apache_shiro.mapper.UserMapper"> <resultMap id="userMap" type="cn.xiangxu.apache_shiro.model.User"> <id property="uid" column="uid"></id> <result property="username" column="username"></result> <result property="password" column="password"></result> <collection property="roleSet" ofType="cn.xiangxu.apache_shiro.model.Role"> <id property="rid" column="rid"></id> <result property="rname" column="rname"></result> <collection property="permissionSet" ofType="cn.xiangxu.apache_shiro.model.Permission"> <id property="pid" column="pid"></id> <result property="pname" column="pname"></result> <result property="purl" column="purl"></result> </collection> </collection> </resultMap> <select id="findByUsername" parameterType="String" resultMap="userMap"> SELECT u.*, p.*, r.* FROM user u INNER JOIN user_role ur ON ur.uid = u.uid INNER JOIN role r ON r.rid = ur.rid INNER JOIN permission_role pr ON pr.rid = r.rid inner JOIN permission p ON p.pid = pr.pid WHERE u.username = #{username} </select> </mapper>
2.5 编写服务接口及实现
package cn.xiangxu.apache_shiro.service; import cn.xiangxu.apache_shiro.model.User; public interface UserService { User findByUsername(String username); }
package cn.xiangxu.apache_shiro.service.serviceImpl; import cn.xiangxu.apache_shiro.mapper.UserMapper; import cn.xiangxu.apache_shiro.model.User; import cn.xiangxu.apache_shiro.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findByUsername(String username) { return userMapper.findByUsername(username); } }
2.6 编写测试类
package cn.xiangxu.apache_shiro.service.serviceImpl; import cn.xiangxu.apache_shiro.model.User; import cn.xiangxu.apache_shiro.service.UserService; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class UserServiceImplTest { @Autowired private UserService userService; @Test public void findByUsername() throws Exception { User user = userService.findByUsername("demo"); System.out.println(user); if (user != null) { log.info("获取用户信息成功"); } else { log.info("获取用户信息失败"); } } }
3 Shiro认证环境搭建
3.1 编写授权、认证登录类
新建一个继承了 AuthorizingRealm 的 AuthRealm类,重写两个 doGetAuthenticationInfo 方法
package cn.xiangxu.apache_shiro; import cn.xiangxu.apache_shiro.model.Permission; import cn.xiangxu.apache_shiro.model.Role; import cn.xiangxu.apache_shiro.model.User; import cn.xiangxu.apache_shiro.service.UserService; import org.apache.commons.collections.CollectionUtils; import org.apache.shiro.authc.*; 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 org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * 自定义授权、认证登录类 */ public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { User user = (User)principalCollection.fromRealm(this.getClass().getName()).iterator().next(); // 从session中获取用户信息 List<String> permissionList = new ArrayList<>(); // 用于存放用户的权限列表 Set<Role> roleSet = user.getRoleSet(); // 从用户信息中获取用户角色 if (CollectionUtils.isNotEmpty(roleSet)) { for (Role role : roleSet) { Set<Permission> permissionSet = role.getPermissionSet(); if (CollectionUtils.isNotEmpty(permissionSet)) { for (Permission permission : permissionSet) { permissionList.add(permission.getPname()); } } } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermissions(permissionList); return info; } // 认证登录(使用用户名和密码进行登录认证) @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)authenticationToken; String username = usernamePasswordToken.getUsername(); // 取出用户名 User user = userService.findByUsername(username); // 根据用户名到数据库中去获取用户信息 return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName()); } }
3.2 编写密码比较类
问题:在AuthRealm类中的认证登录方法中进行密码比较时是将用户输入密码和数据库的密码直接进行比较的,用户输入密码是明文的,但是数据库中的密码是经过加密的,是不能够进行比较的
解决:类支持注入一个 CredentialsMatcher 类型的密码比较器,从AuthRealm的父类doGetAuthenticationInfo 的源码中可以看出;只要通过配置文件将自定义的密码比较类依赖注入到AuthRealm即可
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.apache.shiro.realm; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.Authorizer; import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.permission.PermissionResolver; import org.apache.shiro.authz.permission.PermissionResolverAware; import org.apache.shiro.authz.permission.RolePermissionResolver; import org.apache.shiro.authz.permission.RolePermissionResolverAware; import org.apache.shiro.authz.permission.WildcardPermissionResolver; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.CollectionUtils; import org.apache.shiro.util.Initializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware { private static final Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = ".authorizationCache"; private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); private boolean authorizationCachingEnabled; private Cache<Object, AuthorizationInfo> authorizationCache; private String authorizationCacheName; private PermissionResolver permissionResolver; private RolePermissionResolver permissionRoleResolver; public AuthorizingRealm() { this((CacheManager)null, (CredentialsMatcher)null); } public AuthorizingRealm(CacheManager cacheManager) { this(cacheManager, (CredentialsMatcher)null); } public AuthorizingRealm(CredentialsMatcher matcher) { this((CacheManager)null, matcher); } public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { if (cacheManager != null) { this.setCacheManager(cacheManager); } if (matcher != null) { this.setCredentialsMatcher(matcher); } this.authorizationCachingEnabled = true; this.permissionResolver = new WildcardPermissionResolver(); int instanceNumber = INSTANCE_COUNT.getAndIncrement(); this.authorizationCacheName = this.getClass().getName() + ".authorizationCache"; if (instanceNumber > 0) { this.authorizationCacheName = this.authorizationCacheName + "." + instanceNumber; } } public void setName(String name) { super.setName(name); String authzCacheName = this.authorizationCacheName; if (authzCacheName != null && authzCacheName.startsWith(this.getClass().getName())) { this.authorizationCacheName = name + ".authorizationCache"; } } public void setAuthorizationCache(Cache<Object, AuthorizationInfo> authorizationCache) { this.authorizationCache = authorizationCache; } public Cache<Object, AuthorizationInfo> getAuthorizationCache() { return this.authorizationCache; } public String getAuthorizationCacheName() { return this.authorizationCacheName; } public void setAuthorizationCacheName(String authorizationCacheName) { this.authorizationCacheName = authorizationCacheName; } public boolean isAuthorizationCachingEnabled() { return this.isCachingEnabled() && this.authorizationCachingEnabled; } public void setAuthorizationCachingEnabled(boolean authenticationCachingEnabled) { this.authorizationCachingEnabled = authenticationCachingEnabled; if (authenticationCachingEnabled) { this.setCachingEnabled(true); } } public PermissionResolver getPermissionResolver() { return this.permissionResolver; } public void setPermissionResolver(PermissionResolver permissionResolver) { if (permissionResolver == null) { throw new IllegalArgumentException("Null PermissionResolver is not allowed"); } else { this.permissionResolver = permissionResolver; } } public RolePermissionResolver getRolePermissionResolver() { return this.permissionRoleResolver; } public void setRolePermissionResolver(RolePermissionResolver permissionRoleResolver) { this.permissionRoleResolver = permissionRoleResolver; } protected void onInit() { super.onInit(); this.getAvailableAuthorizationCache(); } protected void afterCacheManagerSet() { super.afterCacheManagerSet(); this.getAvailableAuthorizationCache(); } private Cache<Object, AuthorizationInfo> getAuthorizationCacheLazy() { if (this.authorizationCache == null) { if (log.isDebugEnabled()) { log.debug("No authorizationCache instance set. Checking for a cacheManager..."); } CacheManager cacheManager = this.getCacheManager(); if (cacheManager != null) { String cacheName = this.getAuthorizationCacheName(); if (log.isDebugEnabled()) { log.debug("CacheManager [" + cacheManager + "] has been configured. Building " + "authorization cache named [" + cacheName + "]"); } this.authorizationCache = cacheManager.getCache(cacheName); } else if (log.isInfoEnabled()) { log.info("No cache or cacheManager properties have been set. Authorization cache cannot be obtained."); } } return this.authorizationCache; } private Cache<Object, AuthorizationInfo> getAvailableAuthorizationCache() { Cache<Object, AuthorizationInfo> cache = this.getAuthorizationCache(); if (cache == null && this.isAuthorizationCachingEnabled()) { cache = this.getAuthorizationCacheLazy(); } return cache; } protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { return null; } else { AuthorizationInfo info = null; if (log.isTraceEnabled()) { log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); } Cache<Object, AuthorizationInfo> cache = this.getAvailableAuthorizationCache(); Object key; if (cache != null) { if (log.isTraceEnabled()) { log.trace("Attempting to retrieve the AuthorizationInfo from cache."); } key = this.getAuthorizationCacheKey(principals); info = (AuthorizationInfo)cache.get(key); if (log.isTraceEnabled()) { if (info == null) { log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); } else { log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); } } } if (info == null) { info = this.doGetAuthorizationInfo(principals); if (info != null && cache != null) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } key = this.getAuthorizationCacheKey(principals); cache.put(key, info); } } return info; } } protected Object getAuthorizationCacheKey(PrincipalCollection principals) { return principals; } protected void clearCachedAuthorizationInfo(PrincipalCollection principals) { if (principals != null) { Cache<Object, AuthorizationInfo> cache = this.getAvailableAuthorizationCache(); if (cache != null) { Object key = this.getAuthorizationCacheKey(principals); cache.remove(key); } } } protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1); private Collection<Permission> getPermissions(AuthorizationInfo info) { Set<Permission> permissions = new HashSet(); if (info != null) { Collection<Permission> perms = info.getObjectPermissions(); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } perms = this.resolvePermissions(info.getStringPermissions()); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } perms = this.resolveRolePermissions(info.getRoles()); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } } return permissions.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(permissions); } private Collection<Permission> resolvePermissions(Collection<String> stringPerms) { Collection<Permission> perms = Collections.emptySet(); PermissionResolver resolver = this.getPermissionResolver(); if (resolver != null && !CollectionUtils.isEmpty(stringPerms)) { perms = new LinkedHashSet(stringPerms.size()); Iterator i$ = stringPerms.iterator(); while(i$.hasNext()) { String strPermission = (String)i$.next(); Permission permission = this.getPermissionResolver().resolvePermission(strPermission); ((Collection)perms).add(permission); } } return (Collection)perms; } private Collection<Permission> resolveRolePermissions(Collection<String> roleNames) { Collection<Permission> perms = Collections.emptySet(); RolePermissionResolver resolver = this.getRolePermissionResolver(); if (resolver != null && !CollectionUtils.isEmpty(roleNames)) { perms = new LinkedHashSet(roleNames.size()); Iterator i$ = roleNames.iterator(); while(i$.hasNext()) { String roleName = (String)i$.next(); Collection<Permission> resolved = resolver.resolvePermissionsInRole(roleName); if (!CollectionUtils.isEmpty(resolved)) { ((Collection)perms).addAll(resolved); } } } return (Collection)perms; } public boolean isPermitted(PrincipalCollection principals, String permission) { Permission p = this.getPermissionResolver().resolvePermission(permission); return this.isPermitted(principals, p); } public boolean isPermitted(PrincipalCollection principals, Permission permission) { AuthorizationInfo info = this.getAuthorizationInfo(principals); return this.isPermitted(permission, info); } private boolean isPermitted(Permission permission, AuthorizationInfo info) { Collection<Permission> perms = this.getPermissions(info); if (perms != null && !perms.isEmpty()) { Iterator i$ = perms.iterator(); while(i$.hasNext()) { Permission perm = (Permission)i$.next(); if (perm.implies(permission)) { return true; } } } return false; } public boolean[] isPermitted(PrincipalCollection subjectIdentifier, String... permissions) { List<Permission> perms = new ArrayList(permissions.length); String[] arr$ = permissions; int len$ = permissions.length; for(int i$ = 0; i$ < len$; ++i$) { String permString = arr$[i$]; perms.add(this.getPermissionResolver().resolvePermission(permString)); } return this.isPermitted((PrincipalCollection)subjectIdentifier, (List)perms); } public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) { AuthorizationInfo info = this.getAuthorizationInfo(principals); return this.isPermitted(permissions, info); } protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) { boolean[] result; if (permissions != null && !permissions.isEmpty()) { int size = permissions.size(); result = new boolean[size]; int i = 0; Permission p; for(Iterator i$ = permissions.iterator(); i$.hasNext(); result[i++] = this.isPermitted(p, info)) { p = (Permission)i$.next(); } } else { result = new boolean[0]; } return result; } public boolean isPermittedAll(PrincipalCollection subjectIdentifier, String... permissions) { if (permissions != null && permissions.length > 0) { Collection<Permission> perms = new ArrayList(permissions.length); String[] arr$ = permissions; int len$ = permissions.length; for(int i$ = 0; i$ < len$; ++i$) { String permString = arr$[i$]; perms.add(this.getPermissionResolver().resolvePermission(permString)); } return this.isPermittedAll((PrincipalCollection)subjectIdentifier, (Collection)perms); } else { return false; } } public boolean isPermittedAll(PrincipalCollection principal, Collection<Permission> permissions) { AuthorizationInfo info = this.getAuthorizationInfo(principal); return info != null && this.isPermittedAll(permissions, info); } protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) { if (permissions != null && !permissions.isEmpty()) { Iterator i$ = permissions.iterator(); while(i$.hasNext()) { Permission p = (Permission)i$.next(); if (!this.isPermitted(p, info)) { return false; } } } return true; } public void checkPermission(PrincipalCollection subjectIdentifier, String permission) throws AuthorizationException { Permission p = this.getPermissionResolver().resolvePermission(permission); this.checkPermission(subjectIdentifier, p); } public void checkPermission(PrincipalCollection principal, Permission permission) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkPermission(permission, info); } protected void checkPermission(Permission permission, AuthorizationInfo info) { if (!this.isPermitted(permission, info)) { String msg = "User is not permitted [" + permission + "]"; throw new UnauthorizedException(msg); } } public void checkPermissions(PrincipalCollection subjectIdentifier, String... permissions) throws AuthorizationException { if (permissions != null) { String[] arr$ = permissions; int len$ = permissions.length; for(int i$ = 0; i$ < len$; ++i$) { String permString = arr$[i$]; this.checkPermission(subjectIdentifier, permString); } } } public void checkPermissions(PrincipalCollection principal, Collection<Permission> permissions) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkPermissions(permissions, info); } protected void checkPermissions(Collection<Permission> permissions, AuthorizationInfo info) { if (permissions != null && !permissions.isEmpty()) { Iterator i$ = permissions.iterator(); while(i$.hasNext()) { Permission p = (Permission)i$.next(); this.checkPermission(p, info); } } } public boolean hasRole(PrincipalCollection principal, String roleIdentifier) { AuthorizationInfo info = this.getAuthorizationInfo(principal); return this.hasRole(roleIdentifier, info); } protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) { return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier); } public boolean[] hasRoles(PrincipalCollection principal, List<String> roleIdentifiers) { AuthorizationInfo info = this.getAuthorizationInfo(principal); boolean[] result = new boolean[roleIdentifiers != null ? roleIdentifiers.size() : 0]; if (info != null) { result = this.hasRoles(roleIdentifiers, info); } return result; } protected boolean[] hasRoles(List<String> roleIdentifiers, AuthorizationInfo info) { boolean[] result; if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { int size = roleIdentifiers.size(); result = new boolean[size]; int i = 0; String roleName; for(Iterator i$ = roleIdentifiers.iterator(); i$.hasNext(); result[i++] = this.hasRole(roleName, info)) { roleName = (String)i$.next(); } } else { result = new boolean[0]; } return result; } public boolean hasAllRoles(PrincipalCollection principal, Collection<String> roleIdentifiers) { AuthorizationInfo info = this.getAuthorizationInfo(principal); return info != null && this.hasAllRoles(roleIdentifiers, info); } private boolean hasAllRoles(Collection<String> roleIdentifiers, AuthorizationInfo info) { if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { Iterator i$ = roleIdentifiers.iterator(); while(i$.hasNext()) { String roleName = (String)i$.next(); if (!this.hasRole(roleName, info)) { return false; } } } return true; } public void checkRole(PrincipalCollection principal, String role) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkRole(role, info); } protected void checkRole(String role, AuthorizationInfo info) { if (!this.hasRole(role, info)) { String msg = "User does not have role [" + role + "]"; throw new UnauthorizedException(msg); } } public void checkRoles(PrincipalCollection principal, Collection<String> roles) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkRoles(roles, info); } public void checkRoles(PrincipalCollection principal, String... roles) throws AuthorizationException { this.checkRoles((PrincipalCollection)principal, (Collection)Arrays.asList(roles)); } protected void checkRoles(Collection<String> roles, AuthorizationInfo info) { if (roles != null && !roles.isEmpty()) { Iterator i$ = roles.iterator(); while(i$.hasNext()) { String roleName = (String)i$.next(); this.checkRole(roleName, info); } } } protected void doClearCache(PrincipalCollection principals) { super.doClearCache(principals); this.clearCachedAuthorizationInfo(principals); } }
package cn.xiangxu.apache_shiro; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.SimpleCredentialsMatcher; /** * 自定义密码比较类 */ public class CredentialMather extends SimpleCredentialsMatcher { /** * 用户密码匹配规则 * @param token 用户输入的先关信息 * @param info 根据用户名到数据库中查询到的用户信息 * @return 如果用户输入的密码和数据库中的密码匹配就返回true */ @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token; String password = new String(usernamePasswordToken.getPassword()); // 获取用户输入的密码 String dbPassword = (String)info.getCredentials(); // 获取数据库中的密码 return this.equals(password, dbPassword); // 密码比较并返回 } }
3.3 编写shiro配置类
package cn.xiangxu.apache_shiro; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; /** * Shiro配置类 */ @Configuration public class ShiroConfiguration { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); // 定义登录的url shiroFilterFactoryBean.setSuccessUrl("/index"); // 定义登录成功后的url shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); // 没有权限时跳转的url LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 请求拦截配置 filterChainDefinitionMap.put("/index", "authc"); filterChainDefinitionMap.put("/login", "anon"); // 排除 login 的验证 filterChainDefinitionMap.put("/loginUser", "anon"); // 排除 loginUser 的验证 filterChainDefinitionMap.put("/**", "user"); // 所有请求都必须进行登录过滤 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(authRealm); return defaultWebSecurityManager; } /** 注入自定义密码比较器 */ @Bean public CredentialMather credentialMather() { return new CredentialMather(); } /** 注入自定义的授权、认证登录类 */ @Bean public AuthRealm authRealm(@Qualifier("credentialMather") CredentialMather credentialMather) { AuthRealm authRealm = new AuthRealm(); authRealm.setCredentialsMatcher(credentialMather); return authRealm; } /** Shiro与Spring整合配置 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } }
package cn.xiangxu.apache_shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
/**
* 自定义密码比较类
*/
public class CredentialMather extends SimpleCredentialsMatcher {
/**
* 用户密码匹配规则
* @param token 用户输入的先关信息
* @param info 根据用户名到数据库中查询到的用户信息
* @return 如果用户输入的密码和数据库中的密码匹配就返回true
*/
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
String password = new String(usernamePasswordToken.getPassword()); // 获取用户输入的密码
String dbPassword = (String)info.getCredentials(); // 获取数据库中的密码
return this.equals(password, dbPassword); // 密码比较并返回
}
}