소개:
Shiro는 apache의 오픈 소스 보안 프레임 워크로 , 사용자 인증, 권한, 권한 부여 , 암호화, 세션 관리 및 기타 기능 을 달성하기 위해 보안 인증 소프트웨어 시스템 관련 기능을 끌어내어 공통 보안 인증 프레임 워크를 형성하고 shiro를 사용하여 개발을 완료 할 수 있습니다. 인증, 권한 부여 및 기타 기능을 매우 빠르게 처리하여 시스템 비용을 절감합니다.
요약 구조 :
자세한 구조 :
첫 번째 레이어 : 주제
두 번째 계층 : securiryManager- 관리 구성 요소 작업을 조정하는 데 사용되는 Shiro의 핵심
인증 자 : 인증 관리자- 인증 작업 수행을 담당합니다.
권한 부 여자 : 권한 부여 관리자- 권한 감지 담당
세션 관리 :
세 번째 계층 : 영역-영역은 shiro와 애플리케이션 보안 데이터를 연결하는 다리입니다.
실제 전투 :
配置Shiro安全过滤器
WEB-INF / web.xml
<!-- 配置Shiro安全过滤器 --> <filter> <filter-name>DelegatingFilterProxy</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <!-- 初始化参数 --> <init-param> <param-name>targetBeanName</param-name> <param-value>shiroFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>DelegatingFilterProxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
spring-configs.xml
<!-shiro 프레임 워크 구성->
<!- 영역 개체 구성 (봄에 의해 관리 됨)->
<bean id = "userRealm"
class = "com.jt.sys.service.realm.ShiroUserRealm">
<!-Credential matcher (암호 암호화)->
<property name = "credentialsMatcher">
<bean class = "org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name = "hashAlgorithmName"value = "MD5 "/>
<!-<property name ="hashIterations "value ="1024 "/>->
</ bean>
</ property>
</ bean>
<!-CacheManager 개체를 구성합니다. 성능 향상,인증 정보 및 권한 부여 정보는 캐시 될 수 있습니다.)->
<bean id = "cacheManager"class = "org.apache.shiro.cache.ehcache.EhCacheManager">
<!-이미있는 경우 여기에서 net.sf.ehcache.CacheManager 인스턴스를 설정합니다. 그렇지 않은 경우
기본 구성 으로 새 구성이 생성됩니다.
<property name = "cacheManager"ref = "ehCacheManager"/>->
<!-사전 빌드 된 net.sf.ehcache가없는 경우 .CacheManager 인스턴스를 주입하지만
특정 Ehcache 구성을 사용하려면 여기에서 지정하십시오. 그렇지 않으면 기본값
이 사용됩니다. :->
<property name = "cacheManagerConfigFile"value = "classpath : ehcache.xml"/>
</ bean>
<!-配置securityManager 对象(此 对象 时 shiro框架 核心)->
<bean id = "
class = "org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name = "realm"ref = "userRealm"/>
<property name = "cacheManager"ref = "cacheManager"/>
</ bean>
<! - (자원 요청, 인증 될 릴리스 요청 필터링이 필터 장치를 통해 달성) 구성 shiroFilter > -
<빈 ID = "shiroFilter"클래스 = "org.apache.shiro.spring.web.ShiroFilterFactoryBean을 ">
<!-shiro의 핵심 보안 인터페이스->
<property name ="securityManager "ref ="securityManager "/>
<!- 로그인시 연결 필요 ->
<property name ="loginUrl "값 = "/loginUI.do"> </ property>
<!-성공적인 로그인 후 점프 할 연결 (로그인에서 처리됨)->
<!-<property name = "successUrl"value = "/ index.jsp"> </ property>-- >
<!-권한이없는 리소스에 액세스 할 때 점프 연결
<property name = "unauthorizedUrl"value = "/ default.html"> </ property>->
<!-shiro 연결 제약 구성-->
<property name = "filterChainDefinitions">
<value>
<!-정적 리소스 설정에 대한 익명 액세스 허용->
/ bower_components / ** = anon
/ build / ** = anon
/ dist / ** = anon
/ plugins / ** = anon
/doLogin.do = anon
<!-
Exit- > /doLogout.do = logout <!-주제의 로그 아웃 메서드가 호출되고이 메서드는 세션을 지 웁니다->
<! - 나머지 다른 경로는 액세스하기 전에 인증되어야합니다 .->
/ ** = authc
</ value>
</ property>
</ bean>
<!-Shiro 生命 周期 处理器->
<bean id = "lifecycleBeanPostProcessor"
class = "org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-启用 shiro 注解 权限 检查 (@RequestPermissions)->
<bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on = "lifecycleBeanPostProcessor"/>
<bean class = "org.apache.shiro.spring .security.interceptor.AuthorizationAttributeSourceAdvisor ">
<property name ="securityManager "
ref ="securityManager "/>
</ bean>
인증:
인증 과정 :
- 시스템은 사용자 정보 토큰을 SecurityManager에 제출하기 위해 subject의 로그인 메소드를 호출합니다.
subject.login (토큰)
// 이 요청은 SecurityManager에 제출됩니다.
// SecurityManager 는 인증 프로세서 Authenticator를 호출합니다.
// 인증 프로세서는 인증 정보를 얻기 위해 관련 Realm 객체에 액세스합니다.
- SecurityManager는 인증 작업을 인증 자 개체 Authenticator에 위임합니다.
- 인증자는 ID 정보를 Realm에 전달합니다.
SysUser sysUser = sysUserDao.findUserByUserName (사용자 이름);
- Realm은 데이터베이스에 접근하여 사용자 정보를 얻은 다음 정보를 캡슐화하고 반환합니다.
//3.2 사용자 정보 캡슐화
AuthenticationInfo 정보
= new SimpleAuthenticationInfo (
sysUser.getUsername (), // 마스터 ID
sysUser.getPassword (), // 암호화 된 암호
byteSource, // 솔트에 해당하는 바이트 소스 객체
getName ()); // realm 의 이름
5) 인증자는 영역에서 반환 된 정보를 인증합니다.
SysLoginController.java
@Controller @RequestMapping("/") public class SysLoginController { @Autowired private SysUserService sysUserService; @RequestMapping("loginUI") public String loginUI(){ return "login"; } @RequestMapping("doLogin") @ResponseBody public JsonResult doLogin(String username, String password){ String r=DigestUtils.md5DigestAsHex("123456".getBytes()); System.out.println("r="+r); sysUserService.login(username, password); return new JsonResult("login ok"); } }
@Service public class SysUserServiceImpl implements SysUserService { @Autowired private SysUserDao sysUserDao; @Autowired private SysRoleDao sysRoleDao; @Autowired private SysUserRoleDao sysUserRoleDao; @Override public void login(String username,String password) { System.out.println("service.login"); //0.参数合法性验证 if(StringUtils.isEmpty(username)) throw new ServiceException("用户名不能为空"); if(StringUtils.isEmpty(password)) throw new ServiceException("密码不能为空"); //1.获取Subject(主体)对象 Subject subject=SecurityUtils.getSubject(); //2.封装用户名和密码 UsernamePasswordToken token=new UsernamePasswordToken(username, password); //3.执行身份认证 try { subject.login(token); //此请求会提交给SecurityManager //SecurityManager会调用认证处理器Authenticator //认证处理器会去访问相关Realm对象获取认证信息 } catch (AuthenticationException e) { e.printStackTrace(); throw new ServiceException("用户名或密码不正确"); } //4.记录用户信息 Session session= SecurityUtils.getSubject().getSession(); session.setAttribute("user", username); }
AuthorizingRealm 상속 및 doGetAuthenticationInfo 재정의
Realm을 통한 기본 인증 및 권한 제어 실현
public class ShiroUserRealm extends AuthorizingRealm { @Autowired private SysUserDao sysUserDao; /** * 完成认证信息的获取以及封装 * 此方法何时调用?(执行登陆认证时调用) * @param * 用于接收用户身份以及凭证信息的对象(用户输入的) * * @return AuthenticationInfo * 封装了认证信息的对象(从数据库查询到的) * * client-->controller-->service-->realm */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("realm.doGetAuthenticationInfo"); //1.获取用户身份信息 UsernamePasswordToken uToken= (UsernamePasswordToken)token; String username=uToken.getUsername(); //2.基于用户身份查询数据库信息 SysUser sysUser= sysUserDao.findUserByUserName(username); //3.对查询结果进行封装. //3.1获取用户salt值,并将其转换为一个字节源对象 ByteSource byteSource= ByteSource.Util.bytes(sysUser.getSalt()); //3.2对用户信息进行封装返回. AuthenticationInfo info= new SimpleAuthenticationInfo( sysUser.getUsername(), //主身份 sysUser.getPassword(), //已加密的密码 byteSource,//salt对应的字节源对象 getName());//realm 的名字 return info; } }
public interface SysUserDao { /** * 根据用户名查找用户信息 * @param username * @return */ SysUser findUserByUserName(String username); }
<select id="findUserByUserName" resultType="sysUser"> select * from sys_users where username=#{username} </select>
승인 구현 :
방법:
- 시스템은 주제 관련 메소드 isPermitted를 호출하여 리소스 / hasRole을 기반으로 사용자 정보를 SecurityManager 에 제출합니다.
2) SecurityManager는 권한 감지 작업을 Authorizer 개체 에 위임합니다.
3) 권한 부여자는 사용자 정보를 영역에 위임합니다 .
List <문자열> 목록 = sysUserDao.findUserPermissions (사용자 이름);
- Realm은 데이터베이스에 액세스하여 사용자 권한 정보를 얻고이를 캡슐화합니다 .
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo ();
info.setStringPermissions (permissions);
- 인증자는 사용자 인증 정보를 판단합니다.
@RequiresPermissions ( "sys : user : update")
@RequestMapping("doDeleteObject") @ResponseBody public JsonResult doDeleteObject(String idStr){ sysRoleService.deleteObject(idStr); return new JsonResult(); }
@RequiresPermissions("sys:role:delete") @Override public int deleteObject(String idStr) { //1.参数合法性验证 if(StringUtils.isEmpty(idStr)) throw new ServiceException("必须选中才能删除"); //2.解析字符串 String[] ids=idStr.split(","); //3.调用数据层方法执行删除操作 int rows=sysRoleDao.deleteObject(ids); for(String id:ids){ sysRoleMenuDao.deleteObject(Integer.valueOf(id)); sysUserRoleDao.deleteObject(null, Integer.valueOf(id)); } //4.返回处理结果 if(rows==0) throw new ServiceException("数据已经不存在"); return rows; }
Realm을 통한 기본 인증 및 권한 제어 실현
public class ShiroUserRealm extends AuthorizingRealm { @Autowired private SysUserDao sysUserDao; /*** * 完成授权信息的获取以及封装. * 此方法何时调用?(执行授权检测时调用) * */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { System.out.println("realm.doGetAuthorizationInfo"); //1.获取登陆用户身份信息 String username= (String)principals.getPrimaryPrincipal(); //2.查找用户的权限信息 List<String> list=//sys:user:update,sys:user:view,...., sysUserDao.findUserPermissions(username); System.out.println("list="+list); Set<String> permissions=new HashSet<>(); for(String permission:list){ if(!StringUtils.isEmpty(permission)){ permissions.add(permission); } } System.out.println("set="+permissions); //3.对权限信息进行封装 SimpleAuthorizationInfo info= new SimpleAuthorizationInfo(); info.setStringPermissions(permissions); return info; }
/** * 根据用户id查找用户权限标识信息 * 例如:sys:role:view,sys:role:add * @param userId * @return */ List<String> findUserPermissions(String username);
<select id="findUserPermissions" resultType="string"> select m.permission from sys_users u join sys_user_roles ur join sys_role_menus rm join sys_menus m on u.id=ur.user_id and ur.role_id=rm.role_id and rm.menu_id=m.id where u.username=#{username} </select>
<!-- 整合Shiro 安全框架--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
관련 테이블 :
sys_roles
sys_users
sys_menus
sys_role_menus
sys_user_roles
CREATE TABLE `sys_roles` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL COMMENT '角色名称',
`note` varchar(500) DEFAULT NULL COMMENT '备注',
`createdTime` datetime DEFAULT NULL COMMENT '创建时间',
`modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
`createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
`modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8 COMMENT='角色';CREATE TABLE `sys_users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`salt` varchar(50) DEFAULT NULL COMMENT '盐 密码加密时前缀,使加密后的值不同',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`mobile` varchar(100) DEFAULT NULL COMMENT '手机号',
`valid` tinyint(4) DEFAULT NULL COMMENT '状态 0:禁用 1:正常 默认值 :1',
`createdTime` datetime DEFAULT NULL COMMENT '创建时间',
`modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
`createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
`modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='系统用户';CREATE TABLE `sys_menus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL COMMENT '资源名称',
`url` varchar(200) DEFAULT NULL COMMENT '资源URL',
`type` int(11) DEFAULT NULL COMMENT '类型 1:菜单 2:按钮',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
`parentId` int(11) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
`permission` varchar(500) DEFAULT NULL COMMENT '授权(如:user:create)',
`createdTime` datetime DEFAULT NULL COMMENT '创建时间',
`modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',
`createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',
`modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=141 DEFAULT CHARSET=utf8 COMMENT='资源管理';CREATE TABLE `sys_role_menus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL COMMENT '角色ID',
`menu_id` int(11) DEFAULT NULL COMMENT 'ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1218 DEFAULT CHARSET=utf8 COMMENT='角色与菜单对应关系';CREATE TABLE `sys_user_roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL COMMENT '用户ID',
`role_id` int(11) DEFAULT NULL COMMENT '角色ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8 COMMENT='用户与角色对应关系';INSERT INTO `jt_sys`.`sys_users`(`id`, `username`, `password`, `salt`, `email`, `mobile`, `valid`, `createdTime`, `modifiedTime`, `createdUser`, `modifiedUser`) VALUES (1, 'admin', '4ebd394fbd25e495e0753a7dc9889a8e', '7adb778c-e7d3-4dd3-a3c5-5f80a158006d', '[email protected]', '13624356789', 1, NULL, '2018-01-13 02:06:45', NULL, 'admin');
INSERT INTO `jt_sys`.`sys_menus`(`id`, `name`, `url`, `type`, `sort`, `note`, `parentId`, `permission`, `createdTime`, `modifiedTime`, `createdUser`, `modifiedUser`) VALUES (45, '用户管理', 'user/listUI.do', 1, 45, NULL, 8, 'sys:user:view', '2017-07-12 15:15:59', '2017-07-21 17:36:01', 'admin', 'admin');