您的位置:首页 > 运维架构 > Apache

Shiro学习总结(2)——Apache Shiro快速入门教程

2016-05-09 14:33 639 查看

第一部分 什么是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实际开发中也可以是其他框架

数据库MySQL

准备好所需要的jar放到项目中。

2、创建数据库:

首先需要四张表,分别为 user(用户)、role(角色)、permission(权限)、userRole(用户角色关系表)

这边分别创建四张表的实体类,通过Hiberante的hibernate.hbm2ddl.auto属性的update 来自动生成数据表结构。

[java] view
plain copy

print?





/***

* 用户表

*

* @author Swinglife

*

*/

@Table(name = "t_user")

@Entity

public class User {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

Integer id;

/** 用户名 **/

String username;

/** 密码 **/

String password;

/** 是否删除 **/

Integer isDelete;

/** 创建时间 **/

Date createDate;

//多对多用户权限表

@OneToMany(mappedBy = "user",cascade=CascadeType.ALL)

List<UserRole> userRoles;

省略get set….

}

[java] view
plain copy

print?





/****

* 角色表

*

* @author Swinglife

*

*/

@Entity

@Table(name = "t_role")

public class Role {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

Integer id;

/**角色名**/

String name;

/**角色说明**/

String description;

}

[java] view
plain copy

print?





/****

* 权限表

*

* @author Swinglife

*

*/

@Entity

@Table(name = "t_permission")

public class Permission {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

Integer id;

/**token**/

String token;

/**资源url**/

String url;

/**权限说明**/

String description;

/**所属角色编号**/

Integer roleId;

}

[java] view
plain copy

print?





/***

* 用户角色表

*

* @author Swinglife

*

*/

@Entity

@Table(name = "t_user_role")

public class UserRole {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

Integer id;

@ManyToOne(cascade = CascadeType.ALL)

@JoinColumn(name = "userId", unique = true)

User user;

@ManyToOne

@JoinColumn(name = "roleId", unique = true)

Role role;

}

3、编写操作用户业务的Service:

[java] view
plain copy

print?





@Service

public class AccountService {

/****

* 通过用户名获取用户对象

*

* @param username

* @return

*/

public User getUserByUserName(String username) {

User user = (User) dao.findObjectByHQL("FROM User WHERE username = ?", new Object[] { username });

return user;

}

/***

* 通过用户名获取权限资源

*

* @param username

* @return

*/

public List<String> getPermissionsByUserName(String username) {

System.out.println("调用");

User user = getUserByUserName(username);

if (user == null) {

return null;

}

List<String> list = new ArrayList<String>();

// System.out.println(user.getUserRoles().get(0).get);

for (UserRole userRole : user.getUserRoles()) {

Role role = userRole.getRole();

List<Permission> permissions = dao.findAllByHQL("FROM Permission WHERE roleId = ?", new Object[] { role.getId() });

for (Permission p : permissions) {

list.add(p.getUrl());

}

}

return list;

}

// 公共的数据库访问接口

// 这里省略BaseDao dao的编写

@Autowired

private BaseDao dao;

}

4、编写shiro组件自定义Realm:

[java] view
plain copy

print?





package org.swinglife.shiro;

import java.util.List;

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.authc.UsernamePasswordToken;

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.swinglife.model.User;

import org.swinglife.service.AccountService;

/****

* 自定义Realm

*

* @author Swinglife

*

*/

public class MyShiroRealm extends AuthorizingRealm {

/***

* 获取授权信息

*/

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {

//根据自己系统规则的需要编写获取授权信息,这里为了快速入门只获取了用户对应角色的资源url信息

String username = (String) pc.fromRealm(getName()).iterator().next();

if (username != null) {

List<String> pers = accountService.getPermissionsByUserName(username);

if (pers != null && !pers.isEmpty()) {

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

for (String each : pers) {

//将权限资源添加到用户信息中

info.addStringPermission(each);

}

return info;

}

}

return null;

}

/***

* 获取认证信息

*/

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {

UsernamePasswordToken token = (UsernamePasswordToken) at;

// 通过表单接收的用户名

String username = token.getUsername();

if (username != null && !"".equals(username)) {

User user = accountService.getUserByUserName(username);

if (user != null) {

return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());

}

}

return null;

}

/**用户的业务类**/

private AccountService accountService;

public AccountService getAccountService() {

return accountService;

}

public void setAccountService(AccountService accountService) {

this.accountService = accountService;

}

}

上述类继承了Shiro的AuthorizingRealm类 实现了AuthorizationInfo和AuthenticationInfo两个方法,用于获取用户权限和认证用户登录信息

5、编写LoginController:

[java] view
plain copy

print?





package org.swinglife.controller;

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.subject.Subject;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.portlet.ModelAndView;

import org.swinglife.model.User;

import org.swinglife.service.AccountService;

/****

* 用户登录Controller

*

* @author Swinglife

*

*/

@Controller

public class LoginController {

/***

* 跳转到登录页面

*

* @return

*/

@RequestMapping(value = "toLogin")

public String toLogin() {

// 跳转到/page/login.jsp页面

return "login";

}

/***

* 实现用户登录

*

* @param username

* @param password

* @return

*/

@RequestMapping(value = "login")

public ModelAndView Login(String username, String password) {

ModelAndView mav = new ModelAndView();

User user = accountService.getUserByUserName(username);

if (user == null) {

mav.setView("toLogin");

mav.addObject("msg", "用户不存在");

return mav;

}

if (!user.getPassword().equals(password)) {

mav.setView("toLogin");

mav.addObject("msg", "账号密码错误");

return mav;

}

SecurityUtils.getSecurityManager().logout(SecurityUtils.getSubject());

// 登录后存放进shiro token

UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());

Subject subject = SecurityUtils.getSubject();

subject.login(token);

// 登录成功后会跳转到successUrl配置的链接,不用管下面返回的链接。

mav.setView("redirect:/home");

return mav;

}

// 处理用户业务类

@Autowired

private AccountService accountService;

}

6、编写信息认证成功后的跳转页面:

[java] view
plain copy

print?





package org.swinglife.controller;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

@Controller

public class IndexController {

@RequestMapping("home")

public String index() {

System.out.println("登录成功");

return "home";

}

}

7、Shiro的配置文件.xml

[java] view
plain copy

print?





<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

<property name="securityManager" ref="securityManager" />

<property name="loginUrl" value="/toLogin" />

<property name="successUrl" value="/home" />

<property name="unauthorizedUrl" value="/403" />

<property name="filterChainDefinitions">

<value>

/toLogin = authc <!-- authc 表示需要认证才能访问的页面 -->

/home = authc, perms[/home] <!-- perms 表示需要该权限才能访问的页面 -->

</value>

</property>

</bean>

<bean id="myShiroRealm" class="org.swinglife.shiro.MyShiroRealm">

<property name="accountService" ref="accountService" />

</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

<property name="realm" ref="myShiroRealm"></property>

</bean>

<bean id="accountService" class="org.swinglife.service.AccountService"></bean>

<!-- <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">

<property name="cacheManager" ref="cacheManager" /> </bean> -->

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>user login</h1>

<form action="login" method="post">

username:<input type="text" name="username"><p>

password:<input type="password" name="password">

<p>

${msg }

<input type="submit" value="submit">

</form>

</body>

9、运行程序

在数据库中添加一条用户、角色、以及权限数据,并且在关联表中添加一条关联数据:



在浏览器中访问: home页面 就会跳转到登录页面:



最后输入 账号密码 就会跳转到登录成功页面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: