一,shiro简介
维基百科:Apache Shiro(读作“sheeroh”,即日语“城”)是一个开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。
二,快速搭建
1. 导包(利用Maven)
<properties>
<!--shiro版本号-->
<shiro.version>1.4.0-RC2</shiro.version>
</properties>
<dependencies>
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependencies>
2.建表(数据库采用myBatis)
create table `t_user` (
`id` int (11),
`userName` varchar (60),
`password` varchar (300),
`roleId` int (11)
);
insert into `t_user` (`id`, `userName`, `password`, `roleId`) values('1','ayue','123456','1');
insert into `t_user` (`id`, `userName`, `password`, `roleId`) values('2','aaa','12345','2');
insert into `t_user` (`id`, `userName`, `password`, `roleId`) values('3','bbb','12345',NULL);
insert into `t_user` (`id`, `userName`, `password`, `roleId`) values('4','ccc','12345',NULL);
create table `t_role` (
`id` int (11),
`roleName` varchar (60)
);
insert into `t_role` (`id`, `roleName`) values('1','admin');
insert into `t_role` (`id`, `roleName`) values('2','teacher');
create table `t_permission` (
`id` int (11),
`permissionName` varchar (150),
`roleId` int (11)
);
insert into `t_permission` (`id`, `permissionName`, `roleId`) values('1','user:*','1');
insert into `t_permission` (`id`, `permissionName`, `roleId`) values('2','student:*','2');
3.建立3个实体类
package domain;
/**
* Created by 越 on 2017/4/4.
*/
public class User {
private Integer id;
private String userName;
private String password;
private Integer roleId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
}
package domain;
/**
* Created by 越 on 2017/4/4.
*/
public class Role {
private int id;
private String roleName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
package domain;
/**
* Created by 越 on 2017/4/4.
*/
public class Permission {
private int id;
private String permissionName;
private int roleId;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPermissionName() {
return permissionName;
}
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
}
4. 配置UserMapper.xml
<?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="dao.UserDao">
<resultMap id="BaseResultMap" type="domain.User">
<result property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="password" column="password"/>
<result property="roleId" column="roleId"/>
</resultMap>
<sql id="Base_Column_List">
id, username, password,roleId
</sql>
<select id="findUserByUsername" parameterType="String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from t_user where userName=#{userName}
</select>
<select id="findRoles" parameterType="String" resultType="String">
select r.roleName from t_user u,t_role r where u.roleId=r.id and u.userName=#{userName}
</select>
<select id="findPermissions" parameterType="String" resultType="String">
select p.permissionName from t_user u,t_role r,t_permission p
where u.roleId=r.id and p.roleId=r.id and u.userName=#{userName}
</select>
</mapper>
5. 建立自定义的MyRealm类:用于处理自己的业务逻辑
package shiro;
import domain.User;
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;
import service.UserService;
import javax.annotation.Resource;
import java.util.Set;
/**
* Created by 越 on 2017/4/5.
*/
public class MyRealm extends AuthorizingRealm{
@Resource
private UserService userService;
/**
* 用于权限的认证
* @param principalCollection
* @return
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = principalCollection.getPrimaryPrincipal().toString();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo() ;
Set<String> roleName = userService.findRoles(username);
Set<String> permissions = userService.findPermissions(username);
info.setRoles(roleName);
info.setStringPermissions(permissions);
return info;
}
/**
* 登录验证(先执行)
* @param token
* @return
* @throws AuthenticationException
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取用户账号
String username = token.getPrincipal().toString();
// 从数据库中查询用户信息
User user = userService.findUserByUsername(username);
if (user != null){
// 将查询到的用户名和密码存放到authenticationInfo用于后面的权限判断。第三个参数传入realName。
System.out.println(getName());
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),getName());
return authenticationInfo;
}else
return null;
}
}
6. 与SSM整合
关于如何搭建SSM框架:SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
1. 配置spring-mybatis.xml
<!-- Shiro过滤器 核心-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 身份认证失败,则跳转到登录页面的配置 -->
<property name="loginUrl" value="/jsp/login.jsp"/>
<!-- 权限认证失败,则跳转到指定页面 -->
<property name="unauthorizedUrl" value="/jsp/nopower.jsp"/>
<!-- Shiro连接约束配置,即过滤链的定义 -->
<property name="filterChainDefinitions">
<value>
<!--anon 表示匿名访问,不需要认证以及授权-->
/user/loginAdmin=anon
<!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
/user/admin*=authc
<!--表示访问/student请求的用户必须是teacher角色,不然是不能进行访问的。-->
/user/student=roles[teacher]
<!--表示访问/teacher请求是需要当前用户具有user:create权限才能进行访问的。-->
/user/teacher=perms["user:create"]
</value>
</property>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 开启Shiro注解 -->
<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>
2. UserController
package controller;
import domain.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import service.UserService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* Created by 越 on 2017/3/29.
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/loginAdmin")
public String login(User user,Model model){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassword());
try{
subject.login(token);
return "admin";
}catch (Exception e){
model.addAttribute("error","用户名或密码错误!");
return "login";
}
}
@RequestMapping("/admin")
public String admin(){
return "admin";
}
@RequestMapping("/student")
public String student(){
return "student";
}
@RequestMapping("/teacher")
public String teacher(){
return "teacher";
}
}
3. 页面
login.jsp
<%--
Created by IntelliJ IDEA.
User: 越
Date: 2017/4/8
Time: 15:03
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面</title>
</head>
<body>
<form method="post" action="/user/loginAdmin">
用户名:<input type="text" name="userName"/><br>
密码:<input type="password" name="password"/><br>
<input type="submit" value="登录"/>
</form>
</body>
</html>
admin.jsp
<%--
Created by IntelliJ IDEA.
User: 越
Date: 2017/3/29
Time: 17:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>后台</title>
</head>
<body>
<%--具有admin角色才会显示标签内的信息。--%>
<shiro:hasRole name="admin">
这是admin角色登录:<shiro:principal></shiro:principal>
</shiro:hasRole>
<br>
<%--用户拥有user:create这个权限才回显示--%>
<shiro:hasPermission name="user:create">
有user:create权限信息
</shiro:hasPermission>
<br>
登录成功
</body>
</html>
teacher.jsp
<%--
Created by IntelliJ IDEA.
User: 越
Date: 2017/4/8
Time: 16:50
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>教师</title>
</head>
<body>
访问teacher成功
</body>
</html>
student.jsp
<%--
Created by IntelliJ IDEA.
User: 越
Date: 2017/4/8
Time: 16:50
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>学生</title>
</head>
<body>
访问student成功
</body>
</html>
nopower.jsp
<%--
Created by IntelliJ IDEA.
User: 越
Date: 2017/4/8
Time: 15:23
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>权限认证失败</title>
</head>
<body>
权限认证失败
</body>
</html>
4. web.xml
<!--shiro过滤器定义 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
7. 演示
-
登录:
-
因为ayue是admin角色,且拥有user:create权限,故进入后台页面:
-
访问/user/teacher
-
访问/user/student
3和4的原因在于在spring-mybatis.xml中我们的配置:
<!--表示访问/student请求的用户必须是teacher角色,不然是不能进行访问的。-->
/user/student=roles[teacher]
<!--表示访问/teacher请求是需要当前用户具有user:create权限才能进行访问的。-->
/user/teacher=perms["user:create"]
参考资料:SSM(三)Shiro使用详解