一.shiro权限验证(个人看视频记录的,自己使用,大家参考有不懂可留言)
I.搭建环境
i.导入坐标
xxxxxxxxxx
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
</dependencies>
ii.配置类
ShiroConfig
xxxxxxxxxx
package com.it.fuxinyu.shiro;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
import static com.it.fuxinyu.config.EncryptionMethodAttributes.ENCRYPTION_TIMES;
import static com.it.fuxinyu.config.EncryptionMethodAttributes.MD5;
import static com.it.fuxinyu.config.ShiroPermissionAttributes.*;
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
/*
创建ShiroFilterFactoryBean对 Shiro的过滤器
*/
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
//配置Shiro的过滤器
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/login/login", ANON);
filterMap.put("/image/**", ANON);
filterMap.put("/user/toList", PERMS + "[user:list]");
filterMap.put("/auth/logout", LOGOUt);
filterMap.put("/**", AUTHC);
/**
* 弄登录页
*/
shiroFilterFactoryBean.setLoginUrl("/login/toLogin");
/**
* 未授权页面
*/
shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauthorized");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager 用来管理用户主体的Subject
*
* @return
*/
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager() {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(getUserRealm());
return defaultWebSecurityManager;
}
//shiro的加密使用的是哈希算法+盐加密 我们只需要给他盐和加盐的次数设定加密方式即可
/**
* 实例化自定义的Realm对象
*
* @return
*/
@Bean
public UserRealm getUserRealm() {
UserRealm userRealm = new UserRealm();
userRealm.setCredentialsMatcher(getCredentialsMatcher());
return userRealm;
}
/**
* 加密方法
*
* @return
*/
@Bean
public CredentialsMatcher getCredentialsMatcher() {
//创建HashedCredentialsMatcher对象
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//指定加密方式,可以自定义哈希算法
hashedCredentialsMatcher.setHashAlgorithmName(MD5);
//设置加密次数
hashedCredentialsMatcher.setHashIterations(ENCRYPTION_TIMES);
//设置加密编码:true表示加密使用的是HEX编码 false表示使用的是Base64编码
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
}
ShiroUtils
xxxxxxxxxx
package com.it.fuxinyu.shiro;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
public class ShiroUtils {
/**
* 随机生成 salt 需要指定 它的字符串的长度
*
* @param len 字符串的长度
* @return salt
*/
public static String generateSalt(int len) {
//一个Byte占两个字节
int byteLen = len >> 1;
SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
return secureRandom.nextBytes(byteLen).toHex();
}
/**
* 获取加密后的密码,使用默认hash迭代的次数 1 次
*
* @param hashAlgorithm hash算法名称 MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512、etc。
* @param password 需要加密的密码
* @param salt 盐
* @return 加密后的密码
*/
public static String encryptPassword(String hashAlgorithm, String password, String salt) {
return encryptPassword(hashAlgorithm, password, salt, 1);
}
/**
* 获取加密后的密码,需要指定 hash迭代的次数
*
* @param hashAlgorithm hash算法名称 MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512、etc。
* @param password 需要加密的密码
* @param salt 盐
* @param hashIterations hash迭代的次数
* @return 加密后的密码
*/
public static String encryptPassword(String hashAlgorithm, String password, String salt, int hashIterations) {
SimpleHash hash = new SimpleHash(hashAlgorithm, password, salt, hashIterations);
return hash.toString();
}
}
UserRealm
xxxxxxxxxx
package com.it.fuxinyu.shiro;
import com.it.fuxinyu.pojo.User;
import com.it.fuxinyu.service.UserService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomStringUtils;
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.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权
* <p>
* 校验访问路径
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("-------授权----------");
//编写授权逻辑
//从数据库查询出当前用户所拥有的权限字符串进行授权
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//添加权限字符串
authorizationInfo.addStringPermission("user:list");
return authorizationInfo;
}
/**
* 认证
* <p>
* 进行登录验证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("----------认证----------");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
//调用数据库根据用户名查询出用户
User user = userService.findByName(usernamePasswordToken.getUsername());
if (ObjectUtils.isEmpty(user) || !usernamePasswordToken.getUsername().equals(user.getUserName())) {
return null;
}
/**
* 第一个参数为,假如密码正确就是说登录成功后用户对象,相当于我们以前登陆成功后用户放入session的意思
* 第二个参数,数据库查询出来的密码,shiro会自动帮我们校验密码是否正确
* 第三个参数,假如密码正确也就是说登录成功后用户名
* shiro的加密方式通过盐加次数进行hash加密
* 比如说1234明文,把1234和某一个字符串(盐)一起加密
*/
//判断密码
return new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), user.getUserName());
}
}
iii.工具接口
EncryptionMethodAttributes
xxxxxxxxxx
package com.it.fuxinyu.config;
/**
* 加密方式属性接口
*/
public interface EncryptionMethodAttributes {
/**
* 加密方式MD5
*/
String MD5 = "MD5";
/**
* 加密方式MD4
*/
String MD4 = "MD4";
/**
* 加密方式SHA_1
*/
String SHA_1 = "SHA-1";
/**
* 加密方式SHA_2
*/
String SHA_2 = "SHA-2";
/**
* 加密方式SHA_256
*/
String SHA_256 = "SHA-256";
/**
* 加密方式SHA_512
*/
String SHA_512 = "SHA-512";
/**
* 加密方式SHA_384
*/
String SHA_384 = "SHA-384";
/**
* 加密次数
*/
Integer ENCRYPTION_TIMES = 1;
}
ShiroPermissionAttributes
xxxxxxxxxx
package com.it.fuxinyu.config;
/**
* shiro权限参数
*/
public interface ShiroPermissionAttributes {
/**
* 不需要登录就能访问的路径
*/
String ANON = "anon";
/**
* 需要登录才能访问
*/
String AUTHC = "authc";
/**
* 该资源必须得到资源权限才可以访问
*/
String PERMS = "perms";
/**
* Basic HTTP身份验证拦截器
*/
String AUTHC_BASIC = "authcBasic";
/**
* 退出拦截器。退出成功后会 redirect到设置的/URI
*/
String LOGOUt = "logout";
/**
* 不创建会话连接器
*/
String NO_SESSION_CREATION = "noSessionCreation";
/**
* 端口拦截器
*/
String PORT = "port";
/**
* rest风格拦截器
*/
String REST = "rest";
/**
* 角色拦截器
*/
String ROLES = "roles";
/**
* ssl拦截器。通过https协议才能通过
*/
String SSL = "ssl";
/**
* 用户拦截器 登录后(authc),第二次没登陆但是有记住我(rememberMe)都可以访问
*/
String USER = "user";
}
iV.案例方法
登录
xxxxxxxxxx
@RequestMapping("/login")
public String login(User user, Model model) {
//使用shiro编写登录逻辑
//1.获取subject
Subject subject = SecurityUtils.getSubject();
//2.将参数封装成Token对象
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUserName(), user.getPassword());
//3.执行登录方法
try {
subject.login(usernamePasswordToken);
return "redirect:/index/toIndex";
} catch (IncorrectCredentialsException e) {//这个异常一抛出代表密码错误
model.addAttribute("message", "密码错误");
return "/login";
} catch (AuthenticationException e) { //如果用户不存在,抛出账户位置异常
model.addAttribute("message", "账号不存在");
return "/login";
}
}
回去session中的用户
xxxxxxxxxx
@RequestMapping("/toAdd")
public String toAdd() {
Object principal = SecurityUtils.getSubject().getPrincipal();
User user = null;
if (principal instanceof User) {
user = (User) principal;
}
System.out.println(user);
return "add";
}
II.总结
一上来就把shiro的配置都写好 , 然后在进行操作,以免忘记 过滤器的map必须是linkedHashMap 有顺序的