Shiro(二):Shiro 认证(xml配置方式)
Shiro 认证
一、相关概念
二、Shiro 认证流程
shiro认证流程:
1.获取当前的Subject。调用SecurityUtils.getSubject()方法;
2.测试当前的用户是否已经被认证。即是否已经登录。调用Subject的isAuthenticated()方法;
3.若没有被认证,则把用户名和密码封装为UsernamePasswordToken对象;
如何得到用户名和密码: 1). 创建一个表单页面 2). 把请求提交到SpringMVC 的Handler 3). 获取用户名和密码
4.执行登录:调用Subject 的login(AuthenticationToken)方法;
5.自定义Realm的方法,从数据库中获取对应的记录,返回给Shiro;
自定义Realm的方法: 1).实际上需要继承org.apache.shiro.realm.AuthenticaingRealm类 2).并实现getAuthenticationInfo(AuthenticationToken)方法。
6.由shiro完成对密码的比对。
三、实现认证流程
1.创建表单页面
login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login</title>
</head>
<body>
<h3>login Page</h3>
<form action="login" method="post">
用户名:<input type="text" name="username"/><br><br>
密 码:<input type="password" name="password"/><br><br>
<input type="submit" value="submit"/>
</form>
</body>
</html>
2.编写ShiroHandlerController 类
编写ShiroHandlerController 类,实现登录逻辑处理:
package com.example.shiro.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RestController
public class ShiroHandlerController {
/**
* 进入login页面
* @return
*/
@RequestMapping("/toLogin")
public ModelAndView login(){
return new ModelAndView("login");
}
/**
* 进入list页面
* @return
*/
@RequestMapping("/list")
public ModelAndView list(){
return new ModelAndView("list");
}
/**
* 进入unauthorized页面
* @return
*/
@RequestMapping("/unauthorized")
public ModelAndView unauthorized(){
return new ModelAndView("unauthorized");
}
/**
* 登录
* @param username
* @param password
* @return
*/
@RequestMapping("/login")
public ModelAndView login(@RequestParam("username")String username,@RequestParam("password")String password){
//1.获取当前的Subject
Subject subject=SecurityUtils.getSubject();
//2.判断当前的用户是否已经被认证,即是否已经登录
if(!subject.isAuthenticated()){
//3.若没有被认证,则把username和password封装称UsernamePasswordToken对像
UsernamePasswordToken token=new UsernamePasswordToken(username, password);
//4.执行登录
try {
subject.login(token);
System.out.println("登录成功");
}
//所有认证时异常的父类
catch (AuthenticationException e) {
System.out.println("登录失败:"+e.getMessage());
return new ModelAndView("login");
}
}
return new ModelAndView("list");
}
}
注意:不要忘记在配置文件,需要把登录请求链接放开。
3.实现Realm
实现过程:
1).把AuthenticationToken 转换称 UsernamePasswordToken
2).从UsernamePasswordToken中获取用户名
3).调用数据库方法,从数据库中查询username对应的用户记录
4).判断用户是否存在,若不存在,则抛出UnknownAccountException异常
5).根据用户信息的情况,决定是否需求抛出其他的AutheticationException异常。如用户锁定等
6).根据用户的情况,来构建AuthenticationInfo对像并返回
package com.example.shiro.realms;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.AuthenticatingRealm;
public class ShiroRealm extends AuthenticatingRealm{
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("doGetAuthenticationInfo:"+token);
//1.把AuthenticationToken 转换称 UsernamePasswordToken
UsernamePasswordToken upToken =(UsernamePasswordToken) token;
//2.从UsernamePasswordToken中获取用户名
String username=upToken.getUsername();
//3.调用数据库方法,从数据库中查询username对应的用户记录
System.out.println("从数据库中获取username:"+username+"对应的用户信息");
//4.判断用户是否存在,若不存在,则抛出UnknownAccountException异常
if("unknown".equals(username)){
throw new UnknownAccountException("用户不存在!");
}
//5.根据用户信息的情况,决定是否需求抛出其他的AutheticationException异常。如用户锁定等
if("monster".equals(username)){
throw new LockedAccountException("用户被锁定!");
}
//6.根据用户的情况,来构建AuthenticationInfo对像并返回,通常使用的实现类是SimpleAuthenticationInfo
//以下信息是从数据库获取的
//1).principal:认证的实体类信息。可以是username,也可以是数据表对应的用户的体类对象
Object principal=username;
//2).credentials:密码(数据库获取的用户的密码)
Object credentials="123456";
//3).realmName:当前realm对象的name,调用父类的getName()方法即可
String realmName=getName();
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, realmName);
return info;
}
}
四、测试
1.如果用户名输入unknown,密码任意,则”用户不存在“;
输入用户名unknown,密码1234,控制台输出异常信息:
2.如果用户名输入monster,密码任意,则”用户被锁定“;
输入用户名monster,密码1234,控制台输出异常信息:
3.输入除unknown和monster以外的用户名,密码输入123456,则认证成功(登录成功),否则认证失败(登录失败)
(1)用户名正确,密码错误的情况
输入用户名admin,密码1234,控制台输出异常信息,登录失败
(1)用户名和密码都正确的情况
输入用户名admin,密码123456,登录成功
注意:
输入用户名admin,密码123456,登录成功之后,返回到登录页面,输入其他的任意文字,依然可以进入到了list页面,控制台也没有打印任何信息,这是什么原因呢?
答:原因是 缓存。
想要解决这个问题,需要添加登出功能,来实现用户的切换登录。
如何实现登出?
答:(1)在list.jsp页面添加一个登出链接:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>list</title>
</head>
<body>
<h3>list Page</h3>
<div>欢迎登录</div>
<a href="logout">logout</a>
</body>
</html>
(2)并把登出链接在applicationContext.xml文件的ShiroFilter过滤器中添加一个登出过滤即可
相关文章
- Hive配置Kerberos认证
- rest_framework之认证详解 01
- asp.net core 2.0的认证和授权
- nginx配置ssl加密(单/双向认证、部分https)
- rest framework-认证&权限&限制-长期维护
- django框架进阶-CSRF认证
- .net core 认证与授权(一)
- 谈谈基于OAuth 2.0的第三方认证 [中篇]
- 【快速简单登录认证】SpringBoot使用Sa-Token-Quick-Login插件快速登录认证
- 学习Spring Boot:(十三)配置 Shiro 权限认证
- 7.内网渗透之windows认证机制
- Cookie-based认证实现
- 研发思维07----嵌入式智能产品安全认证必要经过
- 华为交换机 配置Console接口登陆认证