一、新建pageController:
因为SpringBoot项目无法直接访问页面,所以需要配置pageController进行页面的转跳,且Controller层所在的
类不能比启动类层级高或者同级,否则无法自动扫描(如果Controller层所在的类比启动类层级高或者同级可以在启
动类上使用注解@ComponentScan(basePackages = {"包名1", "包名2", ...})指定Controller层所在的包Springboot
2.0.5.RELEASE以上版本支持)。以下展示pageController里面的方法写法:
@RequestMapping("/login")// 请求路径
public String login() {
return "login";// 需要返回的页面
}
二、新建ShiroConfig类用来配置Shiro、UserRealm类用来和数据库交互用来执行认证逻辑和授权逻辑、LoginController用来与前台登录请求交互:
网络图解Shiro执行流程:
三个核心组件:Subject、SecurityManager和Realms。
Subject:
即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐(DaemonAccount)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:
它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm:
Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
1、创建ShiroConfig类:
package com.kingduns.pertes.config.shiro;
import java.util.LinkedHashMap;
import java.util.Map;
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;
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 1、设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 2、设置Shiro内置的安全过滤器,来对相关权限进行拦截
/**
* 常用过滤器
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<String, String>();
/**
* 资源权限过滤器
*/
filterMap.put("/user/addUser", "perms[user:add]");
/*filterMap.put("/addUser", "authc");
filterMap.put("/updateUser", "authc");*/
/**
* 若一个文件夹下的所有页面全部需要拦截可采用通配符
*/
filterMap.put("/user/*", "authc");
filterMap.put("/rsat/login/getLogin", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
// 3、没有权限访问时,转跳到登录页面
shiroFilterFactoryBean.setLoginUrl("/login");
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*
* @return
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
*
* @return
*/
@Bean(name="userRealm")
public UserRealm getRealm() {
return new UserRealm();
}
}
2、创建UserRealm类继承AuthorizingRealm:
package com.kingduns.pertes.config.shiro;
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.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.kingduns.pertes.common.bean.User;
import com.kingduns.pertes.login.service.LoginService;
/**
* 自定义Realm
*
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑(认证用户名和密码)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 1、获取前端页面传过来的用户数据
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 2、查询数据库
User user = loginService.getUserByAccountNumber(usernamePasswordToken.getUsername());
if (user == null) {
// 用户不存在返回null,shiro会报UnknownAccountException
return null;
} else {
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo("", user.getPassword(), "");
return simpleAuthenticationInfo;
}
}
}
3、创建LoginController:
package com.kingduns.pertes.login.controller;
import javax.servlet.http.HttpServletRequest;
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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.kingduns.pertes.common.bean.User;
import com.kingduns.pertes.config.bean.ReturnBean;
import com.kingduns.pertes.login.service.LoginService;
/**
* 用户登录相关业务
*
* @author Administrator
*
*/
@RestController
@RequestMapping("rsat/login")
public class LoginController {
@Autowired
private LoginService loginService;
/**
* 登录
*
* @param accountNumber 账号
* @param passWord 密码
* @return
*/
@RequestMapping("getLogin")
public ReturnBean<User> getLogin(String accountNumber, String passWord, String referrer) {
/*User user = loginService.getLogin(accountNumber, passWord);
if (user != null) {
return new ReturnBean<User>(ReturnBean.SUCCESS, "登录成功!", user);
} else {
return new ReturnBean<User>(ReturnBean.FAIL, "登录失败!", null);
}*/
System.out.println("accountNumber:" + accountNumber);
System.out.println("passWord:" + passWord);
System.out.println("referrer:" + referrer);
// 1、获取Subject
Subject subject = SecurityUtils.getSubject();
// 2、封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(accountNumber, passWord);
// 3、执行登录方法
try {// 若没有出现异常,则登陆成功!
subject.login(token);
return new ReturnBean<User>(ReturnBean.SUCCESS, "登录成功!", null);
} catch (UnknownAccountException e) {
// 用户名不存在
return new ReturnBean<User>(ReturnBean.FAIL, "登录失败,该用户名不存在!", null);
} catch (IncorrectCredentialsException e) {
// 密码错误
return new ReturnBean<User>(ReturnBean.FAIL, "登录失败,密码错误!", null);
}
}
}
以上操作实现了SpringBoot+Shiro+Mybatis用户登录认证