添加依赖
<!-- shiro与spring整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
前端测试代码
<span style="color: red" th:text="${message}"></span>
<form action="/loginController/toLogin" method="post">
用户名:<input name="userName"><br><br>
密码:<input type="password" name="password">
<input type="submit" value="登录">
</form>
controller(控制层)
@RequestMapping("toLogin")
public String toLogin(String userName,String password,Model model){
// 使用shiro 编写登录逻辑
// 1。获取subject
Subject subject = SecurityUtils.getSubject();
//2。将参数封装成token
UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
//3。执行登录
try{
subject.login(token);
return "logins";
}catch (UnknownAccountException e){
model.addAttribute("message","用户不存在");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("message","密码错误");
return "login";
}
}
ShiroConfig(配置类)
@Configuration
public class ShiroConfig {
/*
* 创建 ShiroFilterFactoryBean 对象
* */
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(){
// 创建过滤器
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
//添加shiro 内置过滤器
/*
* shiro 内置过滤器 ,可以实现权限相关的拦截器
*
* 常用的过滤器()
* anon:无需认证可以访问
* authc:必须认证才可以访问
* user: 如果使用rememberme的功能可以访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
* */
Map<String,String> filterMap = new LinkedHashMap<>();
// 放过的路径
filterMap.put("/shiroController/index","anon");
filterMap.put("/loginController/toLogin","anon");//key:访问路径 value:过滤级别
//拦截所有
filterMap.put("/**","authc");
//强行跳转的页面
shiroFilterFactoryBean.setLoginUrl("/loginController/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/*
* 创建 DefaultWebSecurityManager 用来管理用户主体的subject
* */
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(getUserRealm());
return defaultWebSecurityManager;
}
// 使用哈希算法+盐值加密 需要给盐 和 次数
@Bean
public UserRealm getUserRealm(){
UserRealm userRealm = new UserRealm();
userRealm.setCredentialsMatcher(getHashedCredentialsMatcher());
return userRealm;
}
/*
* 设置哈希算法
* */
@Bean
public HashedCredentialsMatcher getHashedCredentialsMatcher() {
//创建hashedCredentialsMatcher 对象
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//指定加密方式 MD4 MD5 SHA-1 SHA-256 SHA-384 SHA-512
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//设置加密次数 必须和UserRealm
hashedCredentialsMatcher.setHashIterations(1);
//设置加密的编码 true:加密使用的是HEX编码 false:base6编码
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
}
UserRealm(认证)
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserServiceI userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
/*
* 执行授权逻辑
* */
System.out.println("》》》》》执行授权逻辑《《《《《《《");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
/*
* 执行认证逻辑
* */
System.out.println("》》》》》》》》》执行认证逻辑《《《《《《《《《《");
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//调用数据库进行验证
TbUser user = userService.findUserInfoByUserName(token.getUsername());
// 编写登录认证逻辑
if (!token.getUsername().equals(user.getTbUserName())){
return null;
}
//判断密码
//假设密码正确,也就是登陆成功后的用户密码,好比将他放入到session中
// 数据库查询出来的密码,shiro自动校验
//加的盐 ByteSource.Util.bytes(user.getTbSalt())
//假设密码正确,也就是登陆成功后的用户名
//盐相当于密钥
//shiro 加密方式 盐+次数 进行哈希加密
//
return new SimpleAuthenticationInfo(user,user.getTbUserPwd(), ByteSource.Util.bytes(user.getTbSalt()),user.getTbUserName());
}
//8fd2fae312c4e621271ea80088cac3a3
public static void main(String[] args) {
String s = ShiroUtils.encryptPassword("MD5", "1234", "c440e502", 1);
System.out.println(s);
}
}
ShiroUtils (随机生成 salt)
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();
}
public static void main(String[] args) {
String s = ShiroUtils.generateSalt(8);
System.out.println(s);
}
}