springboot整合shiro进行注册登录验证

maven坐标

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.5.3</version>
</dependency>

shiro的config类

@Configuration
public class ShiroConfig {

	// 1.创建 shiro filter
	// filter 负责拦截请求的
	@Bean
	public ShiroFilterFactoryBean getShiroFilterBean(DefaultWebSecurityManager defaultSecurityManager) {
		ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
		// 给filter设置安全管理器
		filter.setSecurityManager(defaultSecurityManager);

		Map<String, String> map = new HashMap<String, String>();
        // 配置系统的公共资源
        map.put("/user/login","anon");
		// 配置系统的受限资源,authc是shiro验证过滤器的缩写,代表这个路径需要验证登录
		map.put("/index", "authc");
        // 代表系统内的所有资源都是受限资源
        map.put("/**","authc");
		

		// 将受限资源名单和公共资源名单告诉shiro
		filter.setFilterChainDefinitionMap(map);

		// 默认登录页面,当用户未认证时,shiro就会将用户指向当前路径
		filter.setLoginUrl("/user/login");

		return filter;
	}

	// 2.创建 securityMananger
	@Bean
	public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm) {
		DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
		// 给securityMananger设置realm
		defaultWebSecurityManager.setRealm(realm);
		return defaultWebSecurityManager;
	}

	// 3.创建 自定义realm
	@Bean
	public Realm getRealm() {

		return new CustomerRealm();
	}
}

shiro中常用的过滤器

配置缩写对应的过滤器功能
anonAnonymousFilter指定url可以匿名访问
authcFormAuthenticationFilter指定url可以匿名访问指定url需要form表单登录,默认会从请求中获取username . password , rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。
authcBasicBasicHttpAuthenticationFilter指定url需要basic登录
logoutLogoutFilter登出过滤器,配置指定url就可以实现退出功能,非常方便
noSessionCreationNoSessionCreationFilter禁止创建会话
permsPermissionsAuthorizationFilter需要指定权限才能访问
portPortFilter需要指定端口才能访问
rolesRolesAuthorizationFilter需要指定角色才能访问
sslSslFilter需要https请求才能访问
userUserFilter需要已登录或“记住我”的用户才能访问

完整实例

对用户注册进行md5+salt的编码
对用户登录进行md5+salt的验证

maven依赖

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- jstl表达式支持包 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- jsp引擎 -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<version>9.0.38</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring-boot-starter</artifactId>
			<version>1.5.3</version>
		</dependency>
		<!-- mybatis启动器 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.3</version>
		</dependency>
		<!-- jdbc -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!-- 数据库连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.2.1</version>
		</dependency>
	</dependencies>

application.properties配置

server.port=8080
server.servlet.context-path=/p01

# jsp文件所在路径
spring.mvc.view.prefix=/WEB-INF/jsp/
# jsp文件的后缀名
spring.mvc.view.suffix=.jsp

# 日志配置
logging.level.root=INFO
logging.level.cn.liuhao.springboot_shiro01.**=DEBUG


#数据连接参数
spring.datasource.driveClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.23.128:3306/test_01?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
#数据库连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#指定mybatis要起别名实体类所在的包
mybatis.type-aliases-package=cn.liuhao.springboot_shiro01.pojo
#指定mapper映射文件的文件夹路径
mybatis.mapperLocations=classpath:mappers/*.xml

数据库表

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

user实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {

	private Integer u_id;
	private String u_name;
	private String u_pwd;
	private String u_salt;
	
	// 一个用户可以拥有多条权限
	private List<Permisson> permissons;
}

mapper inteface与mapper.xml

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="cn.liuhao.springboot_shiro01.mapper.UserMapper">
	<insert id="insert" parameterType="user">
		insert into user values (default,#{u_name},#{u_pwd},#{u_salt})
	</insert>
	
	<select id="selectByName" resultType="user" parameterType="java.lang.String">
		select * from user where u_name=#{username}
	</select>
	
	<resultMap type="User" id="userWithRole">
		<id column="u_id" property="u_id" />
		<result column="u_name"  property="u_name" />
		<result column="u_pwd" property="u_pwd" />
		<result column="u_salt" property="u_salt" />
		<collection property="permissons" ofType="cn.liuhao.springboot_shiro01.pojo.Permisson" >
			<id column="p_id" property="p_id" />
			<result column="p_name" property="p_name" />
		</collection>
	</resultMap>
	
	<select id="findUserWithRoleByName" resultMap="userWithRole" parameterType="String" >
		select * from user_permisson_view where u_name=#{username}
	</select>
</mapper>

UserMapper

@Mapper
public interface UserMapper {

	/**
	 * 添加用户
	 * 
	 * @param user
	 * @return
	 */
	public int insert(User user);

	/**
	 * 查找用户
	 * 
	 * @param name
	 * @return
	 */
	public User selectByName(@Param(value = "username") String username);

	/**
	 * 通过用户名查找用户,并将用户的权限一起查出来
	 * 
	 * @param name
	 * @return
	 */
	public User findUserWithRoleByName(@Param(value = "username") String name);

}

service层

UserServiceImpl要先定义一个UserService接口

@Transactional
@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserMapper userMapper;

	@Override
	public boolean addUser(User user) {

		user.setU_salt(SaltUtil.getRandomSalt(10));

		// 使用md5+salt的方式对密码进行编码
		String hex_pwd = new Md5Hash(user.getU_pwd(), user.getU_salt(), 1024).toHex();
		// 将密文存入进数据库
		user.setU_pwd(hex_pwd);

		return userMapper.insert(user) > 0 ? true : false;
	}

	@Override
	public User findUserByName(String name) {

		return userMapper.selectByName(name);
	}

	@Override
	public User getUserWithPermisson(String username) {

		return userMapper.findUserWithRoleByName(username);
	}

}

ShiroConfig

@Configuration
public class ShiroConfig {

	@Autowired
	private CustomerRealm realm;

	// 1.创建 shiro filter
	// filter 负责拦截请求的
	@Bean
	public ShiroFilterFactoryBean getShiroFilterBean(DefaultWebSecurityManager defaultSecurityManager) {
		ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
		// 给filter设置安全管理器
		filter.setSecurityManager(defaultSecurityManager);

		Map<String, String> map = new HashMap<String, String>();
		// 配置系统的受限资源
		map.put("/index", "authc");
		// 配置系统的公共资源

		// 将受限资源名单和公共资源名单告诉shiro
		filter.setFilterChainDefinitionMap(map);

		// 默认登录页面,当用户未认证时,shiro就会将用户指向当前路径
		filter.setLoginUrl("login");

		return filter;
	}

	// 2.创建 securityMananger
	@Bean
	public DefaultWebSecurityManager getDefaultWebSecurityManager(CustomerRealm realm) {
		DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

		// 创建realm使用的hash凭证器
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
		// 告诉凭证器加密的类型
		matcher.setHashAlgorithmName("md5");
		// 告诉凭证器使用hash散列加密的次数
		matcher.setHashIterations(1024);
		// 注入realm
		realm.setCredentialsMatcher(matcher);
		// 给securityMananger设置realm
		defaultWebSecurityManager.setRealm(realm);
		return defaultWebSecurityManager;
	}

}

customRealm

@Slf4j
@Component
public class CustomerRealm extends SimpleAccountRealm {

	@Autowired
	private UserService userService;

	/**
	 * 
	 * 1.从数据库根据名称查找用户,将查找出来的数据与用户提交的进行比对
	 * 
	 * 
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		UsernamePasswordToken principal = (UsernamePasswordToken) token;
		// 从token中给出的信息去查找用户
		User user = userService.findUserByName(principal.getUsername());
		// 不存在用户则返回null
		if (user == null) {

			log.debug("未能找到与用户名" + principal.getUsername() + "相符合的账户");
			return null;
		}
		// 创建authenticationInfo返回
		// 参数1 是用户的身份
		// 参数2 从数据库取出的经过md5和slat加工之后的密码
		// 参数3 从数据库取出用户的slat
		// 参数4 当前realm的name
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal.getPrincipal(),
				user.getU_pwd(), ByteSource.Util.bytes(user.getU_salt()), this.getName());
		return authenticationInfo;
	}

	/**
	 * 根据传递过来的principal从数据库内取出对应用户所有的权限
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		String username = (String) principals.getPrimaryPrincipal();
		// 从数据库中取出对应用户名的用户信息与权限信息
		User userWithPermisson = userService.getUserWithPermisson(username);

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

		// 将权限信息放进authorizationInfo传递给secureMananger
		for (Permisson permisson : userWithPermisson.getPermissons()) {
			authorizationInfo.addStringPermission(permisson.getP_name());
		}

		return authorizationInfo;
	}

}

Controller

@Controller
public class UserController {

	@Autowired
	private UserService userService;

	@RequestMapping("{page_name}")
	public String fun01(@PathVariable("page_name") String page_name) {

		return page_name;
	}

	/**
	 * 登录验证
	 * 
	 * @param uname
	 * @param password
	 * @return
	 */
	@RequestMapping("/user/check")
	public String login(@RequestParam String uname, @RequestParam String password) {

		Subject subject = SecurityUtils.getSubject();
		try {
			subject.login(new UsernamePasswordToken(uname, password));
			return "index";
		} catch (AuthenticationException e) {

			e.printStackTrace();
			return "login";
		}
	}

	@RequestMapping("/user/logout")
	public String logout() {

		Subject subject = SecurityUtils.getSubject();

		subject.logout();

		return "login";
	}

	@RequestMapping("/user/registerCheck")
	public ModelAndView registerCheck(@RequestParam("uname") String uname, @RequestParam("upwd") String upwd) {

		ModelAndView view = new ModelAndView();

		boolean addUser = userService.addUser(new User(null, uname, upwd, null, null));

		view.setViewName(addUser == true ? "login" : "register");

		return view;
	}

}

ProductController

@RequestMapping("product")
public class ProductController {

	@RequestMapping("insert")
	public String insert() {

		Subject subject = SecurityUtils.getSubject();

		if (subject.isPermitted("product:insert")) {
			return "<h1>insert.product.page</h1>";
		}

		return "<h1>用户无权限</h1>";
	}

	@RequestMapping("update")
	public String update() {

		Subject subject = SecurityUtils.getSubject();

		if (subject.isPermitted("product:update")) {
			return "<h1>update.product.page</h1>";
		}

		return "<h1>用户无权限</h1>";
	}

}

结果展示

用户验证截图
在这里插入图片描述
用户授权截图

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值