场景是
我实现了用户在跳转页面如果不经过验证,不能跳转到界面里,那么一般情况下,所有的用户在跳转时都要经过认证,所以就要实现用户认证。如果要查看跳转页面的拦截,请查看:https://blog.youkuaiyun.com/dsl59741/article/details/106419699
用户认证
用户认证的话,需要增加一个登陆页,用来获取用户的用户名和密码,用户认证分两种结果,认证成功和认证失败,认证成功跳转界面,认证失败包括用户不存在和用户存在但是密码错误,还有一般就是会加入用户登录次数限制,有一种用户超过登陆次数用户被锁定的情况,我这里没做。
shiro配置类------和上篇博客一样,没变
package com.kuang.config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//实现登录验证,添加shiro内置过滤器
LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add","authc");//要跳转到add页面的用户必须经过访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
//DefaultSecurityManager
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
//关联realm
defaultSecurityManager.setRealm(userRealm);
return defaultSecurityManager;
}
//创建realm对象 倒着配
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
UserRealm类---------做用户的认证和权限设置【权限设置下篇讲】
package com.kuang.config;
import com.kuang.pojo.User2;
import com.kuang.service.UserService;
import com.kuang.service.UserServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.Subject;
import org.springframework.beans.factory.annotation.Autowired;
//自定义的realm extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserServiceImpl userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权==》doGetAuthorizationInfo");
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证==》doGetAuthorizationInfo");
//获取当前的用户
Subject subject = SecurityUtils.getSubject();
//设置用户名、密码,按理来说应该从数据库中取,但是此时还没有和mybatis整合,所以自己先设置一个
String name = "root";
String password = "root";
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; //把AuthenticationToken转换成真正的UsernamePasswordToken
if(!usernamePasswordToken.getUsername().equals(name)){
return null; //return null就是自动抛出UnKnownAccount 没有此用户的异常
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo("", usernamePasswordToken, ""); //密码认证,shiro自己做,直接把用户输入的token信息传递进去,shiro自动使用SimpleAuthenticationInfo类做密码认证
return simpleAuthenticationInfo;
}
}
controller层-----------添加Login路径映射
package com.kuang.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
@RequestMapping({"/","/index"}) //进入首页
public String toIndex(Model model){
model.addAttribute("msg","hello,shirol");
return "index";
}
@RequestMapping("/user/add") //进入add页面
public String add(){
return "user/add";
}
@RequestMapping("/user/update") //进入update页面
public String update(){
return "user/update";
}
@RequestMapping("/login")
public String login(String username,String password,Model model){
//获取当前的登录用户
Subject subject = SecurityUtils.getSubject();
//封装登录用户的用户名和密码做成UsernameToken,拿到令牌
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
//执行登录方法,经过一系列跳转,然后到UserRealm类的doGetAuthenticationInfo()方法,用户名和密码做认证,如果没有异常就认证成功跳转页面,有异常的话,走shiro底层quickStart的异常登录
try {
subject.login(usernamePasswordToken);
return "index";//登录成功跳转到index界面
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg","密码错误"); //用户名不存在,还是返回Login页
return "login";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名错误");//密码不存在,还是返回Login页
return "login";
}
}
index.html和add.html以及update.html代码同上一篇界面拦截代码
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录</h1>
<hr>
<!--接收从controller传过来的数据-->
<p th:text="${msg}" style="color:red;"></p>
<form th:action="@{/login}">
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
运行:
先走controller层的/tpLogin路径,先进行用户认证,认证成功的话,到Index页面,此时的add页面(加了必须要认证才能访问的权限)此时能进,如下图所示
失败情况、
此时我已经给用户做了登录认证,那么此时我要在跳转到界面时,规定哪些用户能进入哪些页面,哪些不能进入,此时,我需要做权限 认证的功能,详情,请查看这篇博客: