之前我们将用户信息放在了shiro.ini中,将用户的信息写si在了上面,并没有与数据库进行关联,因此我们需要自定义Realm,将用户的信息存放在数据库中。
第一步:建表(并添加用户数据)
第二步:建立Maven项目导入依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- shiro依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<!-- 日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- ============ Servlet ============ -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- ============== SpringMVC ============== -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- spring-jdbc(会传递tx) ,context-support ,aspects-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- spring+mybatis集成依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- mysql驱动 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
<scope>runtime</scope>
</dependency>
<!-- druid依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>
第三步:配置web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--搭建shiro环境
在项目最外层,构建访问控制层
在启动时,初始化shir环境-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--在项目启动时,加载web-info或classpath下的shiro.ini
并且构件webSecurityManager,构建所有配置中使用的过滤器链,ShiroFilter会获取此过滤器链-->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>
第四步:编写Dao层(这里只放dao层的xml内容,dao层接口相对简单就不写出来了)
<?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">
<!--
dtd:docuemtn type definition 为当前提供约束
:标签 属性 层级 顺序
Mapper文件,映射文件,替换DAO实现类
-->
<mapper namespace="cn.itcast.dao.PermissionDao">
<select id="queryAllPermissionByUsername" parameterType="string" resultType="string">
select DISTINCT t_permission.permission_name
from t_user
JOIN t_user_role ON t_user.id = t_user_role.user_id
JOIN t_role on t_role.id = t_user_role.role_id
JOIN t_role_permission ON t_role.id = t_role_permission.role_id
JOIN t_permission ON t_role_permission.permission_id = t_permission.id
WHERE t_user.username=#{username}
</select>
</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">
<!--
dtd:docuemtn type definition 为当前提供约束
:标签 属性 层级 顺序
Mapper文件,映射文件,替换DAO实现类
-->
<mapper namespace="cn.itcast.dao.RoleDao">
<select id="queryAllRolenameByUsername" parameterType="string" resultType="string">
select t_role.role_name
from t_user
JOIN t_user_role ON t_user.id = t_user_role.user_id
JOIN t_role on t_role.id = t_user_role.role_id
WHERE t_user.username=#{username}
</select>
</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">
<!--
dtd:docuemtn type definition 为当前提供约束
:标签 属性 层级 顺序
Mapper文件,映射文件,替换DAO实现类
-->
<mapper namespace="cn.itcast.dao.UserDao">
<select id="queryUserByUsername" parameterType="string" resultType="cn.itcast.domain.User">
select id,username,password
from t_user
where username = #{username}
</select>
</mapper>
第五步:编写自定义Realm
package cn.itcast.realm;
import cn.itcast.domain.User;
import cn.itcast.service.PermissionService;
import cn.itcast.service.RoleService;
import cn.itcast.service.UserService;
import cn.itcast.serviceImpl.UserServiceImpl;
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 org.springframework.web.context.ContextLoader;
import java.util.Set;
public class MyRealm extends AuthorizingRealm {
/*查询权限信息
*何时触发:/user/query=roles["admin"]
* 查询方式通过用户名查询,该用户的权限,角色信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取当前用户的用户名
String username=(String)principals.getPrimaryPrincipal();
RoleService roleService=ContextLoader.getCurrentWebApplicationContext().getBean("roleServiceImpl",RoleService.class);
PermissionService permissionService=ContextLoader.getCurrentWebApplicationContext().getBean("permissionServiceImpl",PermissionService.class);
//查询当前用户信息
Set<String> roles=roleService.queryAllRolenameByUsername(username);
Set<String> perms=permissionService.queryAllPermissionByUsername(username);
//将查询出的信息封装
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo(roles);
simpleAuthorizationInfo.setStringPermissions(perms);
return simpleAuthorizationInfo;
}
/*查询身份信息,
* 查询方式:通过用户名查询用户信息
* 何时触发:subject.login(token)
* 作用:查询身份信息,并返回即可,不用做任何比对
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户登录时发送来的用户名
String username=(String)token.getPrincipal();
//查询用户信息
UserService userService= ContextLoader.getCurrentWebApplicationContext().getBean("userServiceImpl", UserService.class);
User user=userService.queryUserByUsername(username);
if(user==null){//不存在用户名
return null;
}
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),this.getName());
}
}
最后只需要修改我们的realm配置文件即可
[main]
#没有身份认证时,跳转地址
shiro.loginUrl = /user/login
#角色或权限校验不通过时,跳转地址
shiro.unauthorizedUrl=/user/perms/error
#登出后的跳转地址,回首页
shiro.redirectUrl=/
#声明自定义的Realm
realm04=cn.itcast.realm.MyRealm
#将自定义的Realm注册给 核心控制者:Securitymanager
securityManager.realms=$realm04
整个流程大概就是当有请求发送过来时先经过ShiroFilter然后经过一些列的验证,当通过时去调用Realm去进行验证,当验证用过时继续进行下一步操作。