什么是shiro?
如何整合shiro
1.导入依赖
<!--整合shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<!--shiro-thymeleaf-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.编写UserRealm类,继承AuthorizingRealm
package com.fdw.springbootstudy.config;
import com.fdw.springbootstudy.mapper.UserMapper;
import com.fdw.springbootstudy.pojo.User;
import com.fdw.springbootstudy.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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
import java.util.List;
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//拿到当前登录的这个对象
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();
System.out.println("权限:"+user.getPermission());
String[] split = user.getPermission().split(",");
List<String> stringList = Arrays.asList(split);
//设置当前用户的权限,添加多项权限
info.addStringPermissions(stringList);
info.addStringPermission(user.getPermission());
//记得return
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
//用户名认证
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
User user = userService.queryUserByName(userToken.getUsername());
if(user==null){
System.out.println("用户不存在");
return null;//抛出异常
}
//密码认证
//盐:为了即使相同的加密算法不同的盐加密后的结果也不同
ByteSource byteSalt = ByteSource.Util.bytes(user.getName());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPwd(),byteSalt,getName());
return info;
}
}
3.编写配置类ShiroConfig
package com.fdw.springbootstudy.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//shiro三大对象:
// Subject 用户
// SecurityManager 管理用户
// Relam 连接数据
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroBean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证了才能访问
user:必须拥有记住我才能访问
pers:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
Map<String,String> filtermap = new LinkedHashMap<String,String>();
// filtermap.put("/user/add","authc");
// filtermap.put("/user/update","authc");
//设置权限
filtermap.put("/user/add","perms[user:add]");
filtermap.put("/user/update","perms[user:update]");
//设置拦截,且必须先设置授权再设置拦截(重点)
filtermap.put("/user/*","authc");
shiroBean.setFilterChainDefinitionMap(filtermap);
//设置登录的请求
shiroBean.setLoginUrl("/tologin");
//设置未授权的页面
shiroBean.setUnauthorizedUrl("/noauth");
return shiroBean;
}
//DefaultWebsecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象,@Bean默认注入的对象名就是方法名,@Qualifier()可以通过指定对象名来注入
@Bean
public UserRealm userRealm(){
UserRealm userRealm = new UserRealm();
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//设置解密方式,必须和注册时一致
credentialsMatcher.setHashAlgorithmName("MD5");
//解密散列计算2次,必须和注册时一致
credentialsMatcher.setHashIterations(2);
userRealm.setCredentialsMatcher(credentialsMatcher);
return userRealm;
}
//整合ShiroDialect方言:用来整合shiro thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
4. 编写controller类ShiroController
package com.fdw.springbootstudy.controller;
import com.fdw.springbootstudy.mapper.UserMapper;
import com.fdw.springbootstudy.pojo.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.UUID;
@Controller
public class ShiroController {
@Autowired
UserMapper userMapper;
@RequestMapping({"/","/index"})
public String toIndex(Model model){
model.addAttribute("msg","hello,shiro");
return "index";
}
@RequestMapping("/user/add")
public String add(){
return "shiro/add";
}
@RequestMapping("/user/update")
public String update(){
return "shiro/update";
}
@RequestMapping("/tologin")
public String tologin(){
return "shiro/login";
}
@RequestMapping("/login")
public String login(String username,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//加密,封装用户的登录数据(固定套路)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//记住我
//token.setRememberMe(true);
try {
//登录验证
subject.login(token);
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg","用户名错误");
return "shiro/login";
}catch (IncorrectCredentialsException e) {
model.addAttribute("msg","密码错误");
return "shiro/login";
}
}
//打开注册页面
@RequestMapping("/toregister")
public String toregister(){
return "shiro/zhuce";
}
//注册
@RequestMapping("/register")
public String register(String username,String password,Model model){
User user = new User();
user.setName(username);
user.setPermission("user:add");
//密码加密
password = md5encryption(password,username);
System.out.println("密码是:"+password);
user.setPwd(password);
userMapper.addUser(user);
System.out.println("注册成功");
return "shiro/login";
}
@RequestMapping("/noauth")
@ResponseBody
public String unauthorized(){
return "未经授权无法访问此页面";
}
@RequestMapping("/logout")
public String logout(String username,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//注销
subject.logout();
return "index";
}
//加密
public static final String md5encryption(String password, String salt){
//加密方式
String hashAlgorithmName = "MD5";
//盐:为了即使相同的密码不同的盐加密后的结果也不同
ByteSource byteSalt = ByteSource.Util.bytes(salt);
//散列次数
int hashIterations = 2;
SimpleHash result = new SimpleHash(hashAlgorithmName, password, byteSalt, hashIterations);
return result.toString();
}
}
前端页面:
5.效果
未登录时:
登录页面:
登陆成功(MD5加密匹配):
数据库: