前言:
首先感谢我的好朋友-----笔名 鹏仔 引导我入坑,虽然他如今还未毕业
再次感谢我的真正入门老师 Mr Cui,是你让我认识了public static void main(String[]args){system.out.println("Hello worldl")}
,用一段Hello world走进了另一个世界。
其次还要感谢这段路上所有的小伙伴的帮助、调试、Ctrl+c、Ctrl+v,QQ远程,虽然目前增删改查还要再磨磨,太多业务逻辑没有锻炼,但感谢你们的代码,感谢你们的智慧。
最后感谢家人的不计回报的关心爱护,学校至社会,初来乍到,每一步都举步维艰,感谢你们的支持信任
Shiro
1、导入依赖
2、配置文件
3、需要工具:后台SpringBoot+mysql
前台:thymeleaf模板
Shrio三大核心
Subject 用户
SecurityManager 管理所有用户
Realm 连接数据
Demo结构
一、TestController中的配置
RequestMapping("/login")的跳转方法运行时,进行三步操作:
1、获取Subject当前用户
2、获取前台name,password封装成token令牌
@RequestMapping("/login")
public String login(String name,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装当前用户登录数据并封装成token
UsernamePasswordToken token= new UsernamePasswordToken(name,password);
try{
subject.login(token);//执行登录方法,如果没有異常就说明ok了
return "index";
}catch(UnknownAccountException e){//用户名異常
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
}
3、执行异常捕获
try{
subject.login(token);//执行登录方法,如果没有異常就说明ok了
return "index";
}catch(UnknownAccountException e){//用户名異常
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
(1)、try凭借token令牌进入UserRealm类中进行认证
(2)、catch(第一个)块中为token认证完毕后 前台用户名与系统内的用户名不匹配,进而使用model.addAttribute进行存储错误信息,前台展示,并返回到登陆页面
(3)、catch(第二个)块中为token认证完毕,密码不一致时返回的状态,同样返回到登录页面
//controller完整代码
package com.sh.controller;
import org.apache.shiro.SecurityUtils;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
@RequestMapping({"/", "/index"})
public String tologin(Model model) {
model.addAttribute("mes", "Hello shiro");
return "index";
}
@RequestMapping("/user/add")
public String add() {
return "user/add";
}
@RequestMapping("user/updata")
public String updata() {
return "user/updata";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/login")
public String login(String name,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装当前用户登录数据并封装成token
UsernamePasswordToken token= new UsernamePasswordToken(name,password);
try{
subject.login(token);//执行登录方法,如果没有異常就说明ok了
return "index";
}catch(UnknownAccountException e){//用户名異常
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
}
@RequestMapping("/noauth")
@ResponseBody
public String noshouquan(){
return "未经授权不得访问此页面";
}
}
二、ShiroConfig中的配置
注:该类为shiro的全局配置类,下文中UserRealm作为数据连接器会将前台数据传入进行处理,每一步的执行操作在注释上已用数字标识了顺序。
1、创建realm对象(也就是下文中的UserRealm)
//创建Realm对象(1)
@Bean
public UserRealm UserRealm() {
return new UserRealm();
}
2、设置SecurityManager,通过创建DefaultWebSecurityManager 对象关联Realm
//DefaultWebSecurityManager(2)
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
3、
(1)、设置安全管理器
(2)、通过创建Map存放需要
a、拦截的页面
b、访问权限的路径以及权限标识
(3)、//设置登录请求的权限
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
//设置未授权页面
bean.setUnauthorizedUrl("/noauth");
//shiroFilterFactoryBean(3)
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anno:无需认证就可以访问
authc:必须认证了才能访问
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//授权 正常情况会跳到未授权页面
filterMap.put("/user/add", "perms[user:add]");
filterMap.put("/user/updata", "perms[user:updata]");
//设置登录请求的权限
bean.setFilterChainDefinitionMap(filterMap);
//拦截
filterMap.put("/user/*", "authc");
//设置登录的请求
bean.setLoginUrl("/toLogin");
//设置未授权页面
bean.setUnauthorizedUrl("/noauth");
return bean;
}
//ShiroConfig 完整代码
package com.sh.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//shiroFilterFactoryBean(3)
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anno:无需认证就可以访问
authc:必须认证了才能访问
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//授权 正常情况会跳到未授权页面
filterMap.put("/user/add", "perms[user:add]");
filterMap.put("/user/updata", "perms[user:updata]");
//设置登录请求的权限
bean.setFilterChainDefinitionMap(filterMap);
//拦截
filterMap.put("/user/*", "authc");
//设置登录的请求
bean.setLoginUrl("/toLogin");
//设置未授权页面
bean.setUnauthorizedUrl("/noauth");
return bean;
}
//DefaultWebSecurityManager(2)
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建Realm对象(1)
@Bean
public UserRealm UserRealm() {
return new UserRealm();
}
//整合ShiroDialect:用来整合Shiro thymeleaf
@Bean
public ShiroDialect getShiroDialect() {
return new ShiroDialect();
}
}
三、UserRealm中的配置(用以连接用户数据)
1、该类需要继承AuthorizingRealm 父类,初学shiro只重写了两个方法(doGetAuthorizationInfo+doGetAuthenticationInfo)这两个方法的名称非常容易搞混,这两个方法的作用却大相径庭,但功能非常重要,doGetAuthorizationInfo为授权,doGetAuthenticationInfo为认证。前文中token令牌需要认证的地方就是此类的doGetAuthenticationInfo处。
2、doGetAuthenticationInfo(认证)
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=》认证doGetAuthenticationInfo");
//连接真实数据库
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
UserPojo user = service.querUserByName(userToken.getUsername());
if (user == null) {//没有该用户名
return null;
}
//把当前登录用户存入session
Subject currentsubject = SecurityUtils.getSubject();
Session session = currentsubject.getSession();
session.setAttribute("loginuser",user);
//判断密码是否一直
return new SimpleAuthenticationInfo(user, user.getPassword(), "");
}
}
(1)、 此方法接受的参数为前文中的token令牌,通过此令牌实例化对象UserToken,进而通过调用前台name传至后台查询出相应的User实体数据并封装。
(2)、判断用户名:if判断如果查无此数据,直接Return null,此时该方法会捕获异常,并在上文的Controller中进行model存储异常信息处理
(3)、判断密码:在return new SimpleAuthenticationInfo(user, user.getPassword(), “”)中,shiro就可以进行密码判断,判断完毕如果密码不一致自动抛出异常,controller处理同上。
(4)、通过session全局作用域存储当前用户,为后续的首页登录按钮做铺垫
注:通过此上几步,完成了基本的Shiro的用户名与密码的认证
3、doGetAuthorizationInfo(授权)
(1)、创建SimpleAuthorizationInfo 对象
(2)、获取当前用户(此时的用户通过subject.getPrincipal()获取的为认证方法传递过来的用户)
(3)、通过 info.addStringPermission(user.getPerm()),shiro进行权限认证,此权限设置在权限管理器。
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=》授权doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取当前登录用户,该用户从认证里传递而来
Subject subject = SecurityUtils.getSubject();
UserPojo user = (UserPojo)subject.getPrincipal();
//设置权限认证
info.addStringPermission(user.getPerm());
System.out.println(user.getPerm());
return info;
}
//UserRealm完整代码
package com.sh.config;
import com.sh.Service.UserService;
import com.sh.pojo.UserPojo;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
//自定义的UserRealm 继承AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService service;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=》授权doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取当前登录用户,该用户从认证里传递而来
Subject subject = SecurityUtils.getSubject();
UserPojo user = (UserPojo)subject.getPrincipal();
//设置权限认证
info.addStringPermission(user.getPerm());
System.out.println(user.getPerm());
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=》认证doGetAuthenticationInfo");
//连接真实数据库
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
UserPojo user = service.querUserByName(userToken.getUsername());
if (user == null) {//没有该用户名
return null;
}
//把当前登录用户存入session
Subject currentsubject = SecurityUtils.getSubject();
Session session = currentsubject.getSession();
session.setAttribute("loginuser",user);
return new SimpleAuthenticationInfo(user, user.getPassword(), "");
}
}
上述为我学习shiro最基本的操作与理解,也是我的第一篇csdn文,仅此记录、总结我现阶段对shiro的理解,具体学习请前往https://www.bilibili.com/video/BV1PE411i7CV?p=38