Shiro介绍
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
SpringBoot具体整合Shiro的方法如下
1.导入shiro坐标
<!-- Shiro使用Srping框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.2</version>
</dependency>
2.创建ShiroConfig,配置Shiro相关的配置
package com.example.systema.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 1.创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
bean.setLoginUrl("/toLogin"); //设置未登录拦截后的跳转页面,如果不设置该参数,默认跳转到login.jsp
bean.setUnauthorizedUrl("/unAuth"); // 权限认证失败,则跳转到指定页面
// Shiro连接约束配置,即过滤链的定义
Map<String, String> filterMap = new HashMap<>();
filterMap.put("/user/login", "anon");//登录操作放行,不需要认证
filterMap.put("/product/toAdd", "perms[product:add]"); //基于资源的授权过滤器
filterMap.put("/index","user"); //记住我的过滤器
filterMap.put("/**", "authc"); //认证过滤器
bean.setFilterChainDefinitionMap(filterMap); //设置Shiro过滤器
//自定义拦截器
return bean;
}
/**
* 2.创建SecurityManager,并关联Realm
*/
@Bean
public SecurityManager securityManager(UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(userRealm);
// 记住我
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* 3.创建Realm
*/
@Bean
public UserRealm myReal() {
UserRealm myRealm = new UserRealm();
return myRealm;
}
/**
* 开启Shiro注解通知器
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
@Qualifier("securityManager") SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 记住我
*/
public CookieRememberMeManager rememberMeManager()
{
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
/**
* cookie 属性设置
*/
public SimpleCookie rememberMeCookie()
{
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setHttpOnly(true);
cookie.setMaxAge(120);
return cookie;
}
}
3.创建自定义Realm类
package com.example.systema.shiro;
import com.example.systema.domain.User;
import com.example.systema.service.MenuService;
import com.example.systema.service.RoleService;
import com.example.systema.service.UserService;
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.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Set;
public class UserRealm extends AuthorizingRealm {
@Autowired
private MenuService menuService;
@Autowired
private RoleService roleService;
@Autowired
private UserService userService;
/**
* 授权操作
**/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//授权逻辑操作
Object obj = SecurityUtils.getSubject().getPrincipal(); //获取用户信息
User user = (User) obj;
Set<String> roles = new HashSet<String>(); //角色列表
Set<String> menus = new HashSet<String>(); //资源列表
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
roles = roleService.selectRoleKeys(user.getUserId());
menus = menuService.selectPermsByUserId(user.getUserId());
// 角色加入AuthorizationInfo认证对象
info.setRoles(roles);
// 权限加入AuthorizationInfo认证对象
info.setStringPermissions(menus);
return info;
}
/**
* 认证操作
*
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) arg; //获取封装好的前台传递过来的用户信息
User dbUser = userService.findByname(token.getUsername());
if (null == dbUser) {
return null;
}
//校验用户密码,成功返回用户信息
return new SimpleAuthenticationInfo(dbUser, dbUser.getPassword(), "");
}
}
4.创建登录页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h3>用户登录</h3>
<font color="red" th:text="${msg}"></font>
<form method="post" action="/user/login">
用户名:<input type="text" name="userName"/><br/>
密 码:<input type="text" name="password"/><br/>
<input type="submit" value="登录">
记住我:<input type="checkbox" name="rememberMe" value="1">
</form>
</body>
</html>
5.创建Controller类,核心代码是登录的操作
package com.example.systema.controller;
import com.example.systema.domain.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
public String login(User user, Model model, Boolean rememberMe, HttpServletRequest request) {
//SecurityUtils是用于获取实例化SecurityManager的
Subject subject = SecurityUtils.getSubject();
//将前端传递过来的用户信息封装到AuthenticationToken中
// AuthenticationToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
//设置rememberMe功能
if (rememberMe!=null &&rememberMe ==true) {
token.setRememberMe(true);
}
try {
//认证登录操作,如果没有返回任何异常,表示认证成功,如果返回异常表示登录失败,Shiro对返回的异常进行了定义
subject.login(token);
boolean isPermitted = subject.isPermitted("product:add");
System.out.println(isPermitted);
boolean hasRole = subject.hasRole("gjyh");
System.out.println(hasRole);
User dbUser = (User) subject.getPrincipal(); //获取用户用信息
/* request.getSession().setAttribute("userName",dbUser.getUserName());*/
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用戶名不存在");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密碼錯誤");
return "login";
}
return "redirect:/index";
}
/**
* 注销操作
*/
@RequestMapping("/logout")
public String logout() {
Subject subject = SecurityUtils.getSubject();
subject.logout(); //shiro底层将会删除该用户的Session的会话信息
return "redirect:/toLogin";
}
}
具体的数据库表和完整源码可以去我的gitee上下载