第一部分 什么是Apache Shiro
1、什么是 apache shiro :
Apache Shiro是一个功能强大且易于使用的Java安全框架,提供了认证,授权,加密,和会话管理
如同 spring security 一样都是是一个权限安全框架,但是与Spring Security相比,在于他使用了和比较简洁易懂的认证和授权方式。
2、Apache Shiro 的三大核心组件:
1、Subject :当前用户的操作
2、SecurityManager:用于管理所有的Subject
3、Realms:用于进行权限信息的验证
Subject:即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。
SecurityManager:即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。
Realms:Realms则是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。
3、Authentication 和 Authorization
在shiro的用户权限认证过程中其通过两个方法来实现:
1、Authentication:是验证用户身份的过程。
2、Authorization:是授权访问控制,用于对用户进行的操作进行人证授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
4、其他组件:
除了以上几个组件外,Shiro还有几个其他组件:
1、SessionManager :Shiro为任何应用提供了一个会话编程范式。
2、CacheManager :对Shiro的其他组件提供缓存支持。
5、Shiro 完整架构图:
**
**
图片转自:http://kdboy.iteye.com/blog/1154644
第二部分 Apache Shiro 整合Spring的Web程序构建
1、准备工具:
持久层框架:Hibernate4 这边我使用了hibernate来对数据持久层进行操作
控制显示层框架:SpringMVC 这边我使用了SpringMVC实际开发中也可以是其他框架
准备好所需要的jar放到项目中。
2、创建数据库:
首先需要四张表,分别为 user(用户)、role(角色)、permission(权限)、userRole(用户角色关系表)
这边分别创建四张表的实体类,通过Hiberante的hibernate.hbm2ddl.auto属性的update 来自动生成数据表结构。
[java] view plain copy print ?
-
/***
-
*用户表
-
*
-
*@authorSwinglife
-
*
-
*/
-
@Table(name=“t_user”)
-
@Entity
-
publicclassUser{
-
@Id
-
@GeneratedValue(strategy=GenerationType.AUTO)
-
Integerid;
-
/**用户名**/
-
Stringusername;
-
/**密码**/
-
Stringpassword;
-
/**是否删除**/
-
IntegerisDelete;
-
/**创建时间**/
-
DatecreateDate;
-
//多对多用户权限表
-
@OneToMany(mappedBy=“user”,cascade=CascadeType.ALL)
-
ListuserRoles;
-
省略getset….
-
}
[java] view plain copy print ?
-
/****
-
*角色表
-
*
-
*@authorSwinglife
-
*
-
*/
-
@Entity
-
@Table(name=“t_role”)
-
publicclassRole{
-
@Id
-
@GeneratedValue(strategy=GenerationType.AUTO)
-
Integerid;
-
/**角色名**/
-
Stringname;
-
/**角色说明**/
-
Stringdescription;
-
}
[java] view plain copy print ?
-
/****
-
*权限表
-
*
-
*@authorSwinglife
-
*
-
*/
-
@Entity
-
@Table(name=“t_permission”)
-
publicclassPermission{
-
@Id
-
@GeneratedValue(strategy=GenerationType.AUTO)
-
Integerid;
-
/**token**/
-
Stringtoken;
-
/**资源url**/
-
Stringurl;
-
/**权限说明**/
-
Stringdescription;
-
/**所属角色编号**/
-
IntegerroleId;
-
}
[java] view plain copy print ?
-
/***
-
*用户角色表
-
*
-
*@authorSwinglife
-
*
-
*/
-
@Entity
-
@Table(name=“t_user_role”)
-
publicclassUserRole{
-
@Id
-
@GeneratedValue(strategy=GenerationType.AUTO)
-
Integerid;
-
@ManyToOne(cascade=CascadeType.ALL)
-
@JoinColumn(name=“userId”,unique=true)
-
Useruser;
-
@ManyToOne
-
@JoinColumn(name=“roleId”,unique=true)
-
Rolerole;
-
}
3、编写操作用户业务的Service:
[java] view plain copy print ?
-
@Service
-
publicclassAccountService{
-
/****
-
*通过用户名获取用户对象
-
*
-
*@paramusername
-
*@return
-
*/
-
publicUsergetUserByUserName(Stringusername){
-
Useruser=(User)dao.findObjectByHQL(“FROMUserWHEREusername=”,newObject[]{username});
-
returnuser;
-
}
-
/***
-
*通过用户名获取权限资源
-
*
-
*@paramusername
-
*@return
-
*/
-
publicListgetPermissionsByUserName(Stringusername){
-
System.out.println(“调用”);
-
Useruser=getUserByUserName(username);
-
if(user==null){
-
returnnull;
-
}
-
Listlist=newArrayList();
-
//System.out.println(user.getUserRoles().get(0).get);
-
for(UserRoleuserRole:user.getUserRoles()){
-
Rolerole=userRole.getRole();
-
Listpermissions=dao.findAllByHQL(“FROMPermissionWHEREroleId=”,newObject[]{role.getId()});
-
for(Permissionp:permissions){
-
list.add(p.getUrl());
-
}
-
}
-
returnlist;
-
}
-
//公共的数据库访问接口
-
//这里省略BaseDaodao的编写
-
@Autowired
-
privateBaseDaodao;
-
}
4、编写shiro组件自定义Realm:
[java] view plain copy print ?
-
packageorg.swinglife.shiro;
-
importjava.util.List;
-
importorg.apache.shiro.authc.AuthenticationException;
-
importorg.apache.shiro.authc.AuthenticationInfo;
-
importorg.apache.shiro.authc.AuthenticationToken;
-
importorg.apache.shiro.authc.SimpleAuthenticationInfo;
-
importorg.apache.shiro.authc.UsernamePasswordToken;
-
importorg.apache.shiro.authz.AuthorizationInfo;
-
importorg.apache.shiro.authz.SimpleAuthorizationInfo;
-
importorg.apache.shiro.realm.AuthorizingRealm;
-
importorg.apache.shiro.subject.PrincipalCollection;
-
importorg.swinglife.model.User;
-
importorg.swinglife.service.AccountService;
-
/****
-
*自定义Realm
-
*
-
*@authorSwinglife
-
*
-
*/
-
publicclassMyShiroRealmextendsAuthorizingRealm{
-
/***
-
*获取授权信息
-
*/
-
@Override
-
protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionpc){
-
//根据自己系统规则的需要编写获取授权信息,这里为了快速入门只获取了用户对应角色的资源url信息
-
Stringusername=(String)pc.fromRealm(getName()).iterator().next();
-
if(username!=null){
-
Listpers=accountService.getPermissionsByUserName(username);
-
if(pers!=null&&!pers.isEmpty()){
-
SimpleAuthorizationInfoinfo=newSimpleAuthorizationInfo();
-
for(Stringeach:pers){
-
//将权限资源添加到用户信息中
-
info.addStringPermission(each);
-
}
-
returninfo;
-
}
-
}
-
returnnull;
-
}
-
/***
-
*获取认证信息
-
*/
-
@Override
-
protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenat)throwsAuthenticationException{
-
UsernamePasswordTokentoken=(UsernamePasswordToken)at;
-
//通过表单接收的用户名
-
Stringusername=token.getUsername();
-
if(username!=null&&!“”.equals(username)){
-
Useruser=accountService.getUserByUserName(username);
-
if(user!=null){
-
returnnewSimpleAuthenticationInfo(user.getUsername(),user.getPassword(),getName());
-
}
-
}
-
returnnull;
-
}
-
/**用户的业务类**/
-
privateAccountServiceaccountService;
-
publicAccountServicegetAccountService(){
-
returnaccountService;
-
}
-
publicvoidsetAccountService(AccountServiceaccountService){
-
this.accountService=accountService;
-
}
-
}
上述类继承了Shiro的AuthorizingRealm类 实现了AuthorizationInfo和AuthenticationInfo两个方法,用于获取用户权限和认证用户登录信息
5、编写LoginController:
[java] view plain copy print ?
-
packageorg.swinglife.controller;
-
importorg.apache.shiro.SecurityUtils;
-
importorg.apache.shiro.authc.UsernamePasswordToken;
-
importorg.apache.shiro.subject.Subject;
-
importorg.springframework.beans.factory.annotation.Autowired;
-
importorg.springframework.stereotype.Controller;
-
importorg.springframework.web.bind.annotation.RequestMapping;
-
importorg.springframework.web.bind.annotation.RequestMethod;
-
importorg.springframework.web.portlet.ModelAndView;
-
importorg.swinglife.model.User;
-
importorg.swinglife.service.AccountService;
-
/****
-
*用户登录Controller
-
*
-
*@authorSwinglife
-
*
-
*/
-
@Controller
-
publicclassLoginController{
-
/***
-
*跳转到登录页面
-
*
-
*@return
-
*/
-
@RequestMapping(value=“toLogin”)
-
publicStringtoLogin(){
-
//跳转到/page/login.jsp页面
-
return"login";
-
}
-
/***
-
*实现用户登录
-
*
-
*@paramusername
-
*@parampassword
-
*@return
-
*/
-
@RequestMapping(value=“login”)
-
publicModelAndViewLogin(Stringusername,Stringpassword){
-
ModelAndViewmav=newModelAndView();
-
Useruser=accountService.getUserByUserName(username);
-
if(user==null){
-
mav.setView(“toLogin”);
-
mav.addObject(“msg”,“用户不存在”);
-
returnmav;
-
}
-
if(!user.getPassword().equals(password)){
-
mav.setView(“toLogin”);
-
mav.addObject(“msg”,“账号密码错误”);
-
returnmav;
-
}
-
SecurityUtils.getSecurityManager().logout(SecurityUtils.getSubject());
-
//登录后存放进shirotoken
-
UsernamePasswordTokentoken=newUsernamePasswordToken(user.getUsername(),user.getPassword());
-
Subjectsubject=SecurityUtils.getSubject();
-
subject.login(token);
-
//登录成功后会跳转到successUrl配置的链接,不用管下面返回的链接。
-
mav.setView(“redirect:/home”);
-
returnmav;
-
}
-
//处理用户业务类
-
@Autowired
-
privateAccountServiceaccountService;
-
}
6、编写信息认证成功后的跳转页面:
[java] view plain copy print ?
-
packageorg.swinglife.controller;
-
importorg.springframework.stereotype.Controller;
-
importorg.springframework.web.bind.annotation.RequestMapping;
-
@Controller
-
publicclassIndexController{
-
@RequestMapping(“home”)
-
publicStringindex(){
-
System.out.println(“登录成功”);
-
return"home";
-
}
-
}
7、Shiro的配置文件.xml
[java] view plain copy print ?
-
<beanid="shiroFilter"class=“org.apache.shiro.spring.web.ShiroFilterFactoryBean”>
-
<propertyname="securityManager"ref=“securityManager”/>
-
<propertyname=“loginUrl"value=”/toLogin"/>
-
<propertyname=“successUrl"value=”/home"/>
-
<propertyname=“unauthorizedUrl"value=”/403"/>
-
<propertyname=“filterChainDefinitions”>
-
/toLogin=authc
-
/home=authc,perms[/home]
-
<beanid="myShiroRealm"class=“org.swinglife.shiro.MyShiroRealm”>
-
<propertyname="accountService"ref=“accountService”/>
-
<beanid="securityManager"class=“org.apache.shiro.web.mgt.DefaultWebSecurityManager”>
-
<propertyname="realm"ref=“myShiroRealm”>
-
<beanid="accountService"class=“org.swinglife.service.AccountService”>
loginUrl 用于配置登陆页
successUrl 用于配置登录成功后返回的页面,不过该参数只会在当登录页面中并没有任何返回页面时才会生效,否则会跳转到登录Controller中的指定页面。
unauthorizedUrl 用于配置没有权限访问页面时跳转的页面
filterChainDefinitions:apache shiro通过filterChainDefinitions参数来分配链接的过滤,资源过滤有常用的以下几个参数:
1、authc 表示需要认证的链接
2、perms[/url] 表示该链接需要拥有对应的资源/权限才能访问
3、roles[admin] 表示需要对应的角色才能访问
4、perms[admin:url] 表示需要对应角色的资源才能访问
8、登陆页login.jsp
[html] view plain copy print ?
-
<body>
-
<h1>userlogin</h1>
-
<formaction="login"method=“post”>
-
username:<inputtype="text"name=“username”><p>
-
password:<inputtype="password"name=“password”>
-
<p>
-
${msg}
-
<inputtype="submit"value=“submit”>
-
</form>
-
</body>
9、运行程序
在数据库中添加一条用户、角色、以及权限数据,并且在关联表中添加一条关联数据:
在浏览器中访问: home页面 就会跳转到登录页面:
转载出处:
最后输入 账号密码 就会跳转
shiro jar:http://download.csdn.net/detail/swingpyzf/8766673
项目源码:github:https://github.com/swinglife/shiro_ex