springmvc集成shiro(java安全框架)

什么是shiro

Apache Shiro是一个强大且易用的Java开源安全框架,拥有登录认证、授权管理、企业级会话管理和加密等功能。相比 spring Security 来说要更加的简单。

主要三个核心组件:Subject,SecurityManager 和 Realms

Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。

SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

pom.xml文件

<properties>
	<!-- Spring版本号 -->
	<spring.version>5.1.5.RELEASE</spring.version>
	<!-- json包jackson-annotations版本号 -->
	<jackson.version>2.9.8</jackson.version>
	<!-- shiro版本号 -->
	<shiro.version>1.3.2</shiro.version>
</properties>

<dependencies>
	<!-- slf4j-nop -->
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-nop</artifactId>
		<version>1.7.2</version>
	</dependency>
	<!-- junit -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
	</dependency>
	<!-- spring core 核心 -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!--spring bean bean的管理 -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-beans</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!--spring context -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!--spring context support -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context-support</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring web -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring mvc -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring tx -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-tx</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring jdbc -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring El表达式 -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-expression</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- spring test -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<!-- mybatis -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.4.6</version>
	</dependency>
	<!-- mybatis-spring -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis-spring</artifactId>
		<version>1.3.2</version>
	</dependency>
	<!-- mysql-connector-java -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.47</version>
	</dependency>
	<!-- log4j -->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<!-- json包jackson-databind -->
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>${jackson.version}</version>
	</dependency>
	<!-- json包jackson-core -->
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-core</artifactId>
		<version>${jackson.version}</version>
	</dependency>
	<!-- json包jackson-annotations -->
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-annotations</artifactId>
		<version>${jackson.version}</version>
	</dependency>
	<!-- jstl -->
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>jstl</artifactId>
		<version>1.2</version>
	</dependency>
	<!-- 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>
	<dependency>
		<groupId>org.apache.shiro</groupId>
		<artifactId>shiro-ehcache</artifactId>
		<version>${shiro.version}</version>
	</dependency>
	<!-- shiro的依赖结束 -->
</dependencies>

jdbc.properties配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_shiro
jdbc.username=root
jdbc.password=root

spring-context.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">

	<!-- 开启注解扫描,对包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
	<context:component-scan base-package="com.shiro" />

	<!-- 开启注解驱动,启动基于Spring MVC的注解功能,将控制器与方法映射加入到容器中 -->
	<mvc:annotation-driven />

	<!-- 配置Spring MVC视图解析器 -->
	<bean id="ViewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean>

</beans>

spring-mybatis.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- 读取数据库连接的配置文件 -->
	<context:property-placeholder
		location="classpath:jdbc.properties" />

	<!-- 开启注解扫描,并开启注解驱动,用于测试 -->
	<!-- <context:component-scan base-package="com.shiro" />
	<context:annotation-config /> -->

	<!-- 创建数据源,连接数据库 -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<!-- 创建sqlSessionFactory工厂,在工厂中依赖数据源,将数据源映射到sqlSessionFactory中 -->
	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 配置别名,不用在mybatis-config.xml配置文件中配置别名 -->
		<property name="typeAliasesPackage" value="com.shiro.entity" />
		<!-- ref中的dataSource是<bean id="dataSource">创建数据源,连接数据库的id值 -->
		<property name="dataSource" ref="dataSource" />
		<!-- 获得所有的mapper文件,自动扫描mapping.xml文件 -->
		<property name="mapperLocations" value="classpath:mappers/*.xml" />
	</bean>

	<!-- 配置dao接口所在的包。DAO接口所在包名,Spring会自动查找其下的类 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 得到所有的dao接口文件,与mapper文件进行对应的映射 -->
		<property name="basePackage" value="com.shiro.dao" />
		<!-- 依赖sqlSessionFactory工厂 -->
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>

	<!-- 事务管理器(由Spring管理MyBatis的事务) -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 关联数据源 -->
		<property name="dataSource" ref="dataSource" />
	</bean>

</beans>

spring-shiro.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 項目自定义的Realm,从数据库中获取用户的安全数据 -->
	<bean id="myShiroRealm" class="com.shiro.utils.MyRealm" />

	<!-- 用户授权信息Cache(缓存) -->
	<bean id="cacheManager"
		class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />

	<!-- 配置安全管理器securityManager, 缓存技术: 缓存管理 realm:负责获取处理数据 -->
	<bean id="securityManager"
		class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="myShiroRealm" />
		<property name="cacheManager" ref="cacheManager" />
	</bean>

	<!-- shiro的核心配置(自定义权限校验): 配置shiroFileter id名必须与web.xml中的filtername保持一致 -->
	<bean id="shiroFilter"
		class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- Shiro的核心安全接口,这个属性是必须的 -->
		<property name="securityManager" ref="securityManager" />
		<!-- 身份认证失败,跳转到登录页面的配置 -->
		<property name="loginUrl" value="/user/login" />
		<!-- Shiro的核心安全接口,这个属性是必须的 -->
		<property name="successUrl" value="/user/list" />
		<!-- 权限认证失败,跳转到指定页面 -->
		<property name="unauthorizedUrl" value="/unauthorized.jsp" />
		<!-- Shiro连接约束配置,即过滤链的定义 -->
		<property name="filterChainDefinitions">
			<value>
				<!--anon 表示匿名访问,不需要认证以及授权 -->
				/user/login = anon
				/user/dologin = anon
				/user/list = authc
				<!-- /api/** = anon -->
				<!-- 表示访问/admin请求的用户必须是admin角色,不然是不能进行访问的 -->
				<!-- /admin/** = roles[admin] -->
				<!-- 表示访问/teacher请求是需要当前用户具有user:create权限才能进行访问的 -->
				<!-- /teacher=perms["user:create"] -->
				/user/loginOut=logout <!-- 退出登录 -->
				<!--authc表示需要认证 没有进行身份认证是不能进行访问的,必须放在最后 -->
				/** = authc
			</value>
		</property>
	</bean>

	<!-- 必须配置lifecycleBeanPostProcessor为了管理shiro中常见的对象 -->
	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor"
		class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<!-- 开启Shiro注解 -->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		depends-on="lifecycleBeanPostProcessor" />
</beans>

web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">

	<!-- 可以用 contextloaderlistener + Alt + / 自动生成<context-param>和<listener> -->
	<!-- 配置上下文路径参数 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-*.xml</param-value>
	</context-param>
	<!-- 配置上下文监听器 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- 可以用 dispatcherservlet + Alt + / 自动生成<servlet>和<servlet-mapping> -->
	<servlet>
		<servlet-name>shiro</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 设置spring-context.xml的路径 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-context.xml</param-value>
		</init-param>
		<!-- 1表示启动项目就加载这个类 -->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>shiro</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- 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>

	<!-- 设置字符编码格式过滤器 -->
	<filter>
		<filter-name>characterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<!-- 设置编码格式为UTF-8 -->
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<!-- 强制修改字符编码 -->
			<param-name>forceRequestEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<!-- 所有请求都要经过该过滤器 -->
	<filter-mapping>
		<filter-name>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>

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">
<!-- namespace用接口的全路径作为命名空间 -->
<mapper namespace="com.shiro.dao.UserDao">

	<!-- 查询用户全部信息 -->
	<select id="list" resultType="User">
		select * from t_user
	</select>

	<!-- 根据用户名来查询用户信息 -->
	<select id="findUserByUsername" parameterType="java.lang.String" resultType="User">
		select * from t_user where username=#{username}
	</select>

	<!-- 根据用户名来查询角色信息 -->
	<select id="findRoles" parameterType="java.lang.String" resultType="java.lang.String">
		select r.role_name from
		t_user u,t_role r,t_user_role ur
		where u.id = ur.userid
		and r.role_id = ur.roleid
		and u.username = #{username}
	</select>

	<!-- 根据用户名来查询权限信息 -->
	<select id="findPermissions" parameterType="java.lang.String" resultType="java.lang.String">
		select p.permission_name from
		t_user u,t_role r,t_permission p,t_user_role ur,t_role_permission rp
		where u.id = ur.userid
		and r.role_id = ur.roleid
		and r.role_id = rp.roleid
		and rp.permissionid = p.permission_id
		and u.username = #{username}
	</select>

</mapper>

Md5Util加密工具类

package com.shiro.utils;

import org.apache.shiro.crypto.hash.Md5Hash;

public class Md5Util {

	// 基于shiro的MD5加密,加密结果为32位小写
	public static String md5(String str) {
		return new Md5Hash(str).toString();
	}

}

MyRealm工具类

package com.shiro.utils;

import java.util.Set;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
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.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.shiro.entity.User;
import com.shiro.service.UserService;

public class MyRealm extends AuthorizingRealm {

	@Resource
	private UserService userService;

	// 用户授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String username = principals.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;
	}

	// 登录认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 获取用户账号
		String username = token.getPrincipal().toString();
		User user = userService.findUserByUsername(username);
		if (user != null) {
			// 如果查询到了,封装查询结果
			Object principal = user.getUsername();
			Object credentials = user.getPassword();
			String realmName = this.getName();
			String salt = user.getUsername();
			ByteSource byteSalt = ByteSource.Util.bytes(salt);// 根据用户名加盐
			AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal, credentials, byteSalt,
					realmName);
			return authenticationInfo;
		} else {
			return null;
		}
	}

	// 清空当前用户权限信息
	public void clearCachedAuthorizationInfo() {
		PrincipalCollection principalCollection = SecurityUtils.getSubject().getPrincipals();
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principalCollection, getName());
		super.clearCachedAuthorizationInfo(principals);
	}

	// 指定清除principalCollection
	public void clearCachedAuthorizationInfo(PrincipalCollection principalCollection) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principalCollection, getName());
		super.clearCachedAuthorizationInfo(principals);
	}

}

User实体

package com.shiro.entity;

public class User {

	private int id;
	private String username;
	private String password;
	private String phone;
	private String nickname;
	private String email;

	public User() {
		super();
	}

	public int getId() {
		return id;
	}

	public void setId(int 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 String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + ", phone=" + phone
				+ ", nickname=" + nickname + ", email=" + email + "]";
	}

}

UserDao层

package com.shiro.dao;

import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Repository;

import com.shiro.entity.User;

@Repository
public interface UserDao {

	// 查询用户全部信息
	List<User> list();

	// 根据用户名来查询用户信息
	User findUserByUsername(String username);

	// 根据用户名来查询角色信息
	Set<String> findRoles(String username);

	// 根据用户名来查询权限信息
	Set<String> findPermissions(String username);

}

UserService接口

package com.shiro.service;

import java.util.List;
import java.util.Set;

import com.shiro.entity.User;

public interface UserService {

	// 查询用户全部信息
	List<User> list();

	// 根据用户名来查询用户信息
	User findUserByUsername(String username);

	// 根据用户名来查询角色信息
	Set<String> findRoles(String username);

	// 根据用户名来查询权限信息
	Set<String> findPermissions(String username);

}

UserServiceImpl实现类

package com.shiro.service.impl;

import java.util.List;
import java.util.Set;

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

import com.shiro.dao.UserDao;
import com.shiro.entity.User;
import com.shiro.service.UserService;

@Service("userService")
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;

	@Override
	public List<User> list() {
		return userDao.list();
	}

	@Override
	public User findUserByUsername(String username) {
		return userDao.findUserByUsername(username);
	}

	@Override
	public Set<String> findRoles(String username) {
		return userDao.findRoles(username);
	}

	@Override
	public Set<String> findPermissions(String username) {
		return userDao.findPermissions(username);
	}

}

UserController层

package com.shiro.controller;

import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
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.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.shiro.entity.User;
import com.shiro.service.UserService;
import com.shiro.utils.Md5Util;

@Controller
@RequestMapping("user")
public class UserController {

	@Autowired
	private UserService userService;

	@GetMapping("login")
	public String login() {
		return "login";
	}

	@PostMapping("dologin")
	@ResponseBody
	public boolean dologin(User user, boolean rememberMe) {
		boolean loginflag = false;
		// 创建Subject实例对象
		Subject currentUser = SecurityUtils.getSubject();
		// 判断当前用户是否已登录
		if (!currentUser.isAuthenticated()) {
			UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),
					Md5Util.md5(user.getPassword()));
			System.out.println(token);
			boolean flag = false;
			try {
				token.setRememberMe(rememberMe);
				currentUser.login(token);
				loginflag = true;
			} catch (DisabledAccountException dax) {
				System.out.println("用户名为:" + dax.getMessage() + " 用户已经被禁用!");
				flag = true;
			} catch (ExcessiveAttemptsException eae) {
				System.out.println("用户名为:" + eae + " 用户登录次数过多,有暴力破解的嫌疑!");
				flag = true;
			} catch (AuthenticationException ae) {
				System.out.println("------------------身份认证失败-------------------");
				flag = true;
			} catch (Exception e) {
				System.out.println("未知异常信息。。。。");
				flag = true;
			}
			if (flag) {
				return loginflag;
			}
		}
		return loginflag;
	}

	@GetMapping("list")
	public String list(Model model) {
		List<User> users = userService.list();
		model.addAttribute("users", users);
		return "user/list";
	}

	@GetMapping("loginOut")
	public String loginOut() {
		return "redirect:/user/login";
	}

}

login.jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.Date" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<% pageContext.setAttribute("date", new Date()); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui-v2.5.3/css/layui.css" />
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://www.layuicdn.com/layer-v3.1.0/layer.js"></script>
</head>
<body>
<div class="layui-row layui-col-space5">
	<div class="layui-col-md4">
		<div class="grid-demo grid-demo-bg1"></div>
	</div>
	<div class="layui-col-md4">
		<div class="grid-demo">
			<fieldset class="layui-elem-field layui-field-title"
				style="margin-top: 50px;">
				<legend>用户登录</legend>
				<span style="padding-left: 30px;color: pink;">
					<fmt:formatDate value="${date }" pattern="yyyy年MM月dd日"/>
				</span>
			</fieldset>
			<form>
				<span id="msg" style="margin-left: 18%; color: red"></span>
				<div style="margin-left: -20px;">
					<div class="layui-form-item">
						<label class="layui-form-label">用户名:</label>
						<div class="layui-input-block">
							<input type="text" name="username" id="username" lay-verify="title" autocomplete="off" class="layui-input">
						</div>
					</div>
					<div class="layui-form-item">
						<label class="layui-form-label">密&nbsp;&nbsp;&nbsp;&nbsp;码:</label>
						<div class="layui-input-block">
							<input type="password" name="password" id="password" lay-verify="title" autocomplete="off" class="layui-input">
						</div>
					</div>
					<div class="layui-form-item">
						<div class="layui-input-block">
							<button type="button" id="login"
							class="layui-btn layui-btn-lg layui-btn-primary layui-btn-radius">立即登录</button>
							<button style="float: right" type="button" id="register"
							class="layui-btn layui-btn-lg layui-btn-primary layui-btn-radius">没有账号?</button>
						</div>
					</div>
				</div>
			</form>
		</div>
	</div>
	<div class="layui-col-md4">
		<div class="grid-demo grid-demo-bg1"></div>
	</div>
</div>
<script type="text/javascript">
	$(function() {
		$("#login").on("click", function() {
			var username = $("#username").val();
			var password = $("#password").val();
			if(!username) {
				$("#msg").html("用户名不能为空!");
				$("#username").focus();
				return false;
			} else {
				if(!password) {
					$("#msg").html("密码不能为空!");
					$("#password").focus();
					return false;
				} else {
					$("#msg").html("");
				}
			}
			$.ajax({
				type: "post", // post或get
				url: "${pageContext.request.contextPath}/user/dologin", // 提交路径
				data: {
					username: username,
					password: password
				},
				success: function(data) {
					console.log(data);
					if (data == true) {
						layer.msg('登录中', {
							icon: 16
							,shade: 0.01
						});
						// 延迟跳转
						window.setTimeout("window.location='${pageContext.request.contextPath}/user/list'",1000); 
					} else {
						layer.tips('用户名或密码错误!', '#login', {
							tips: [2, '#3595CC'],
							time: 2000
						});
					}
				},
				error: function(err) {
					layer.msg('数据异常!');
				}
			})
		});
		$("#register").on("click", function() {
			layer.msg('数据异常!');
		});
	})
</script>
<!-- <script>
	// 防止点击页面后退
	history.pushState(null, null, document.URL);
	window.addEventListener('popstate', function() {
		history.pushState(null, null, document.URL);
	});
</script> -->
</body>
</html>

user的list.jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户列表</title>
</head>
<body>
欢迎[ <shiro:principal/> ]登录用户列表&nbsp;&nbsp;&nbsp;&nbsp;
<a href="${pageContext.request.contextPath}/user/loginOut">退出</a>
<hr>
<c:forEach items="${users}" var="user">
	${user.id} ----> ${user.username} ----> ${user.phone} ----> ${user.email}<br>
</c:forEach>
</body>
</html>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springboot:是一个基于Java开发的框架,简化了Spring应用的初始化配置和部署过程。它提供了一套开发规范和约定,帮助开发人员快速搭建高效稳定的应用程序。 mybatis-plus:是基于MyBatis的增强工具,提供了一些便捷的CRUD操作方法和代码生成功能,简化了数据库操作的开发工作。它能够轻松集成到SpringBoot应用中,提高开发效率。 springmvc:是一种基于MVC设计模式的Web框架,用于构建Web应用程序。它能够从URL中解析请求参数,并将请求分发给对应的Controller进行处理。SpringMVC提供了一套灵活的配置和注解方式,支持RESTful风格的API开发。 shiro:是一种用于身份验证和授权的框架,可以集成到SpringBoot应用中。它提供了一套简单易用的API,可以处理用户认证、角色授权、会话管理等安全相关的功能。Shiro还支持集成其他认证方式,如LDAP、OAuth等。 redis:是一种开源的内存数据库,采用键值对存储数据。Redis具有高性能、高并发和持久化等特点,常用于缓存、消息队列和分布式锁等场景。在企业级报表后台管理系统中,可以使用Redis来进行缓存数据,提高系统的响应速度和性能。 企业级报表后台管理系统:是一种用于统一管理和生成报表的系统。它通常包括用户权限管理、报表设计、报表生成、数据分析等功能。使用SpringBoot、MyBatis-Plus、SpringMVCShiro和Redis等技术,可以快速搭建一个可靠、高效的报表管理系统,满足企业对数据分析和决策的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值