一、代码未动,依赖先行
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
二、实现Realm类
package com.example.shiro1.shiro;
import com.example.shiro1.dto.PermissionDTO;
import com.example.shiro1.dto.RoleDTO;
import com.example.shiro1.dto.UserDTO;
import com.example.shiro1.entity.User;
import com.example.shiro1.service.RoleService;
import com.example.shiro1.service.UserService;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author: kang
* @Company: 康康小课堂
* @DateTime: 2020-07-18-19:04
* @Description: 描述
*/
public class MyShiroRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
/**
* 设置授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("开始授权(doGetAuthorizationInfo)");
//获取登录用户名
String name = (String) principals.getPrimaryPrincipal();
//根据用户名去数据库查询用户信息
UserDTO user = userService.getUserDTOByName(name);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for(RoleDTO dto: user.getRoles()){
//添加角色
simpleAuthorizationInfo.addRole(dto.getRoleName());
//添加权限
for(PermissionDTO permission : dto.getPermissions()){
simpleAuthorizationInfo.addStringPermission(permission.getName());
}
}
return simpleAuthorizationInfo;
}
/**
* 设置认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("开始认证(doGetAuthenticationInfo)");
//加这一步的目的是在Post请求的时候会先进认证,然后再请求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
UserDTO user = userService.getUserDTOByName(name);
if (user == null) {
//这里返回后会报出对应异常
return null;
}
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
三、实现Shiro的配置类
package com.example.shiro1.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.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author: kang
* @Company: 康康小课堂
* @DateTime: 2020-07-18-19:16
* @Description: 描述
*/
@Configuration
public class ShiroConfiguration {
/**
* anno:无需认证(登陆)可以访问
* authc:必须认证才能访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限可以访问
* role:该资源必须得到角色权限才能访问
*/
private Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
/**
* Filter工厂,设置对应的过滤条件和跳转条件
* @param securityManager
* @return
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
logger.info("进入shiroFilter......");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置不需要拦截的路径
Map<String,String> map = new LinkedHashMap<String, String>();
//按顺序依次判断
map.put("/static/**", "anon");
/************************************初始化所有的权限信息开始******************************************/
//这里可以直接配置访问所需权限
//filterChainDefinitionMap.put("/user/list", "authc,perms[user:list]");
//filterChainDefinitionMap.put("/user/add", "authc,perms[user:add]");
map.put("/**", "authc");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
map.put("/logout", "logout");
/***************************************初始化所有的权限信息结束*********************************************/
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/main");
//未授权界面
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
/**
* 将自己的验证方式加入容器
* @return
*/
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
//这里可以设置缓存的机制
return myShiroRealm;
}
/**
* 权限管理,配置主要是Realm的管理认证
* @return
*/
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
注:配置ShiroConfiguration时可能会报错–
Incompatible types.
Required: java.lang.SecurityManager
Found: org.apache.shiro.web.mgt.DefaultWebSecurityManager
此时只需要手动导入如下包即可
import org.apache.shiro.mgt.SecurityManager;
四、配置LoginController
package com.example.shiro1.controller;
import com.example.shiro1.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author: kang
* @Company: 康康小课堂
* @DateTime: 2020-07-18-19:32
* @Description: 描述
*/
@Controller
public class LoginController {
private Logger logger = LoggerFactory.getLogger(LoginController.class);
/**
* 进入登录界面
* @return login
*/
@GetMapping("/login")
public String getLogin(){
logger.info("进入login页面");
return "login";
}
@RequestMapping("/index")
public String index(){
return "index";
}
/***********************************************************************************************************/
/**************************************** shiro功能练习 ************************************/
/***********************************************************************************************************/
/**
* 点击登录后的操作
* @param user 用户
* @return
*/
@PostMapping("/post/login")
public String doLogin(@RequestBody User user) {
logger.info("进入登录处理");
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
user.getUsername(),
user.getPassword()
);
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
//subject.checkRole("admin");
//subject.checkPermissions("query", "add");
} catch (AuthenticationException e) {
e.printStackTrace();
return "账号或密码错误!";
} catch (AuthorizationException e) {
e.printStackTrace();
return "没有权限";
}
return "main";
}
/**
* 注解验角色和权限
*/
@RequiresRoles("超级管理")
@RequiresPermissions("系统管理")
@RequestMapping("/goMain")
public String goMain() {
return "main";
}
}
注:常用注解
@RequiresAuthenthentication:表示当前Subject已经通过login进行身份验证;即 Subjec.isAuthenticated()返回 true
@RequiresUser:表示当前Subject已经身份验证或者通过记住我登录的,
@RequiresGuest:表示当前Subject没有身份验证或者通过记住我登录过,即是游客身份
@RequiresRoles(value = {“admin”,”user”},logical = Logical.AND):表示当前Subject需要角色admin和user
@RequiresPermissions(value = {“user:delete”,”user:b”},logical = Logical.OR):表示当前Subject需要权限user:delete或者user:b
五、整合Thymeleaf
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<hr>
<ul>
<li><a href="user/index">个人中心</a></li>
<li><a href="vip/index">会员中心</a></li>
<p shiro:hasPermission="svip"><li>这是svip能看到的p标签</li></p>
<shiro:hasPermission name="svip"><li>这是svip能看到的</li></shiro:hasPermission>
<li><a href="logout">退出登录</a></li>
</ul>
</body>
</html>
注:常用标签
shiro:guest
游客访问user 标签:用户已经通过认证\记住我 登录后显示响应的内容
shiro:user
欢迎[shiro:principal/]登录 退出authenticated标签:用户身份验证通过,即 Subjec.login 登录成功 不是记住我登录的
shiro:authenticted
用户[shiro:principal/] 已身份验证通过notAuthenticated标签:用户未进行身份验证,即没有调用Subject.login进行登录,包括”记住我”也属于未进行身份验证
shiro:notAuthenticated
未身份验证(包括”记住我”)principal 标签:显示用户身份信息,默认调用
Subjec.getPrincipal()获取,即Primary Principal
<shiro:principal property = “username”/>hasRole标签:如果当前Subject有角色将显示body体内的内容
<shiro:hashRole name = “admin”>
用户[shiro:principal/]拥有角色adminhasAnyRoles标签:如果Subject有任意一个角色(或的关系)将显示body体里的内容
<shiro:hasAnyRoles name = “admin,user”>
用户[shiro:pricipal/]拥有角色admin 或者 userlacksRole:如果当前 Subjec没有角色将显示body体内的内容
<shiro:lacksRole name = “admin”>
用户[shiro:pricipal/]没有角色adminhashPermission:如果当前Subject有权限将显示body体内容
<shiro:hashPermission name = “user:create”>
用户[shiro:pricipal/] 拥有权限user:createlacksPermission:如果当前Subject没有权限将显示body体内容
<shiro:lacksPermission name = “org:create”>
用户[shiro:pricipal/] 没有权限org:create