分析Shrio的核心API
Subject:用戶主體(把操作交給SecurityManager)
SecurityManager:安全管理器(關(guān)聯(lián)Realm)
Realm:Shiro連接數(shù)據(jù)的橋梁
Spring Boot整合Shiro
(1) 導(dǎo)入依賴
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0></version>
<dependency/>
(2)自定義Realm類
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定義Realm
*/
public class UserRealm extends AuthorizingRealm {
/**
* 執(zhí)行授權(quán)邏輯
* @param principalCollection
* @return
*/
//@Qualifier("userRealm")將userRealm注入當(dāng)前類
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("執(zhí)行授權(quán)邏輯");
return null;
}
/**
* 執(zhí)行認(rèn)證邏輯
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執(zhí)行認(rèn)證邏輯");
return null;
}
}
(3)編寫Shiro配置類(*)
建立shiro的配置類
/**
* shiro配置類
*/
@Configuration
public class ShiroConfig {
/**
* 創(chuàng)建ShiroFilterFactoryBean
*/
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設(shè)置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
/**
* 創(chuàng)建DefaultWebSecurityManager
*/
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
//@Qualifier("userRealm")將userRealm注入當(dāng)前類
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//關(guān)聯(lián)realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創(chuàng)建Realm
*/
@Bean
public UserRealm getRealm(){
return new UserRealm();
}
(4) 使用Shiro內(nèi)置過濾器實(shí)現(xiàn)頁面攔截,在ShiroConfig中配置
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設(shè)置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shrio內(nèi)置過濾器
/**
* Shiro內(nèi)置過濾器,可以實(shí)現(xiàn)權(quán)限相關(guān)的攔截器
* 常用的過濾器:
* anon:無需認(rèn)證(登錄)可以訪問
* authc:必須認(rèn)證才可以訪問
* user:如果使用rememberMe的功能可以直接訪問
* perms:該資源必須得到資源權(quán)限才可以訪問
* role:該資源必須得到角色權(quán)限才可以訪問
*/
Map<String ,String> filterMap = new LinkedHashMap<>();
// filterMap.put("/add","authc");
// filterMap.put("/update","authc");
filterMap.put("/login","anon");
filterMap.put("/tologin","anon");
filterMap.put("/getinfo","anon");
filterMap.put("/*","authc");
shiroFilterFactoryBean.setLoginUrl("/tologin"); //自定義設(shè)置攔截跳轉(zhuǎn)登錄頁面,默認(rèn)是login.jsp
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
UserController中設(shè)置登錄
@PostMapping (value = "/login")
public String login(String name,String password,Model model){
/**
* 使用Shiro編寫認(rèn)證操作
*/
//1.獲取SUbject
Subject subject = SecurityUtils.getSubject();
//2分裝用戶數(shù)據(jù)
UsernamePasswordToken token = new UsernamePasswordToken(name,password);
//3.執(zhí)行登錄方法
try {
subject.login(token);
//登錄成功
return "redirect:getinfo";
} catch (UnknownAccountException e) { //UnknownAccountException shiro用戶名不存在拋異常
// e.printStackTrace();
//登錄失敗
model.addAttribute("msg","用戶名不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//e.printStackTrace();
//登錄失敗
model.addAttribute("msg","密碼錯(cuò)誤");
return "login";
}
在UserRealm中,執(zhí)行認(rèn)證邏輯中,編寫登錄邏輯
/**
* 執(zhí)行認(rèn)證邏輯
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執(zhí)行認(rèn)證邏輯");
//假設(shè)數(shù)據(jù)庫的用戶名和密碼 模擬數(shù)據(jù)庫
String name = "liwei";
String password = "123456";
//編寫shiro判斷邏輯,判斷用戶名和密碼
//1.判斷用戶名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
if(!token.getUsername().equals(name)){
//用戶名不存在
return null; //shiro底層會(huì)拋出UnKnowAccountExceeption
}
//2 判斷密碼
return new SimpleAuthenticationInfo("",password,"");
}
整合mybatis
添加依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
編寫application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.108.128:3306/tensquare_user
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource #druid數(shù)據(jù)源
mybatis:
type-aliases-package: com.liwei.domain #配置實(shí)體路徑在mapper.xml中,返回實(shí)體可以不用寫前置路徑
mapper-locations: mapperXml/*.xml
在啟動(dòng)類上加掃mapper(dao)注解
@SpringBootApplication
@MapperScan("com.liwei.shiro.mapper")
public class ShiroApplication {
public static void main(String[] args) {
SpringApplication.run(ShiroApplication.class);
}
}
mapper
public interface UserMapper {
User findByMobil(String mobile);
}
service
public interface UserService {
User findByMobil(String mobile);
}
serviceimpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByMobil(String mobile) {
return userMapper.findByMobil(mobile);
}
}
controller
@PostMapping (value = "/login")
public String login(String mobile,String password,Model model){
/**
* 使用Shiro編寫認(rèn)證操作
*/
//1.獲取SUbject
Subject subject = SecurityUtils.getSubject();
//2分裝用戶數(shù)據(jù)
UsernamePasswordToken token = new UsernamePasswordToken(mobile,password);
//3.執(zhí)行登錄方法
try {
subject.login(token);
//登錄成功
return "redirect:getinfo";
} catch (UnknownAccountException e) {
// e.printStackTrace();
//登錄失敗
model.addAttribute("msg","用戶名不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//e.printStackTrace();
//登錄失敗
model.addAttribute("msg","密碼錯(cuò)誤");
return "login";
}
}
}
在自定義Realm中編寫登錄驗(yàn)證
/**
* 自定義Realm
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 執(zhí)行授權(quán)邏輯
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("執(zhí)行授權(quán)邏輯");
return null;
}
/**
* 執(zhí)行認(rèn)證邏輯
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執(zhí)行認(rèn)證邏輯");
//假設(shè)數(shù)據(jù)庫的用戶名和密碼 模擬數(shù)據(jù)庫
//編寫shiro判斷邏輯,判斷用戶名和密碼
//1.判斷用戶名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = userService.findByMobil(token.getUsername());
if(user==null){
//用戶名不存在
return null; //shiro底層會(huì)拋出UnKnowAccountExceeption
}
//2 判斷密碼
return new SimpleAuthenticationInfo("",user.getPassword(),"");
}
}
使用shiro內(nèi)置過濾器攔截資源
/**
* shiro配置類
*/
@Configuration
public class ShiroConfig {
/**
* 創(chuàng)建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設(shè)置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shrio內(nèi)置過濾器
/**
* Shiro內(nèi)置過濾器,可以實(shí)現(xiàn)權(quán)限相關(guān)的攔截器
* 常用的過濾器:
* anon:無需認(rèn)證(登錄)可以訪問
* authc:必須認(rèn)證才可以訪問
* user:如果使用rememberMe的功能可以直接訪問
* perms:該資源必須得到資源權(quán)限才可以訪問
* role:該資源必須得到角色權(quán)限才可以訪問
*/
Map<String ,String> filterMap = new LinkedHashMap<>();
// filterMap.put("/add","authc");
// filterMap.put("/update","authc");
filterMap.put("/login","anon");
filterMap.put("/tologin","anon");
filterMap.put("/getinfo","anon");
filterMap.put("/*","authc");
TODO授權(quán)過濾器
// 注意:當(dāng)前授權(quán)攔截后,shiro會(huì)自動(dòng)跳轉(zhuǎn)到未授權(quán)頁面
filterMap.put("/user/add","perms[user:add]"); // user/add 攔截的路徑名
//設(shè)置未授權(quán)提示頁面
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth"); //自定義的提示頁面路徑 /noauth 路徑請(qǐng)求地址
shiroFilterFactoryBean.setLoginUrl("/tologin"); //自定義設(shè)置攔截跳轉(zhuǎn)登錄頁面,默認(rèn)是login.jsp
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 創(chuàng)建DefaultWebSecurityManager
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
//@Qualifier("userRealm")將userRealm注入當(dāng)前類
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//關(guān)聯(lián)realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創(chuàng)建Realm
*/
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
實(shí)現(xiàn)數(shù)據(jù)庫動(dòng)態(tài)綁定
在數(shù)據(jù)庫中添加一個(gè)權(quán)限字段
perms 數(shù)值設(shè)置為:user:add user:update user:delete
#### 增加依賴 實(shí)現(xiàn)thymeleaf動(dòng)態(tài)標(biāo)簽
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
**
* 自定義Realm
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 執(zhí)行授權(quán)邏輯
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("執(zhí)行授權(quán)邏輯");
//給資源進(jìn)行授權(quán)
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加資源的授權(quán)字符串
//info.addStringPermission("user:add");
//到數(shù)據(jù)庫查詢當(dāng)前登錄用戶的授權(quán)字符串
//獲取當(dāng)前登錄用戶
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
User dbUser = userService.findById(user.getId());
info.addStringPermission(dbUser.getPerms()); //設(shè)置授權(quán)字段號(hào)
return info;
}
/**
* 執(zhí)行認(rèn)證邏輯
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執(zhí)行認(rèn)證邏輯");
//假設(shè)數(shù)據(jù)庫的用戶名和密碼 模擬數(shù)據(jù)庫
//編寫shiro判斷邏輯,判斷用戶名和密碼
//1.判斷用戶名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = userService.findByMobil(token.getUsername());
if(user==null){
//用戶名不存在
return null; //shiro底層會(huì)拋出UnKnowAccountExceeption
}
//2 判斷密碼
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
配置攔截器信息
@Configuration
public class ShiroConfig {
/**
* 創(chuàng)建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設(shè)置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shrio內(nèi)置過濾器
/**
* Shiro內(nèi)置過濾器,可以實(shí)現(xiàn)權(quán)限相關(guān)的攔截器
* 常用的過濾器:
* anon:無需認(rèn)證(登錄)可以訪問
* authc:必須認(rèn)證才可以訪問
* user:如果使用rememberMe的功能可以直接訪問
* perms:該資源必須得到資源權(quán)限才可以訪問
* role:該資源必須得到角色權(quán)限才可以訪問
*/
Map<String ,String> filterMap = new LinkedHashMap<>();
// filterMap.put("/add","authc");
// filterMap.put("/update","authc");
filterMap.put("/login","anon");
filterMap.put("/tologin","anon");
filterMap.put("/getinfo","anon");
filterMap.put("/*","authc");
//對(duì)用戶的修改功能進(jìn)行授權(quán)
filterMap.put("/user/update","perms[user:update]");
//授權(quán)過濾器
// 注意:當(dāng)前授權(quán)攔截后,shiro會(huì)自動(dòng)跳轉(zhuǎn)到未授權(quán)頁面
filterMap.put("/user/add","perms[user:add]");
//設(shè)置未授權(quán)提示頁面
shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
shiroFilterFactoryBean.setLoginUrl("/tologin"); //自定義設(shè)置攔截跳轉(zhuǎn)登錄頁面,默認(rèn)是login.jsp
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 創(chuàng)建DefaultWebSecurityManager
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
//@Qualifier("userRealm")將userRealm注入當(dāng)前類
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//關(guān)聯(lián)realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 創(chuàng)建Realm
*/
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
/**
* 配置shiroDialect,用于thymeleaf和shiro標(biāo)簽配合使用
*/
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
controller
@Autowired
private UserService userService;
@GetMapping("/noauth")
public String noauth(){
return "/noauth";
}
@PostMapping (value = "/login")
public String login(String mobile,String password,Model model){
/**
* 使用Shiro編寫認(rèn)證操作
*/
//1.獲取SUbject
Subject subject = SecurityUtils.getSubject();
//2分裝用戶數(shù)據(jù)
UsernamePasswordToken token = new UsernamePasswordToken(mobile,password);
//3.執(zhí)行登錄方法
try {
subject.login(token);
//登錄成功
return "redirect:getinfo";
} catch (UnknownAccountException e) {
// e.printStackTrace();
//登錄失敗
model.addAttribute("msg","用戶名不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//e.printStackTrace();
//登錄失敗
model.addAttribute("msg","密碼錯(cuò)誤");
return "login";
}
}
}
前端頁面--結(jié)合動(dòng)態(tài)標(biāo)簽實(shí)現(xiàn)隱藏連接,有增加的用戶看不到修改的
<!DOCTYPE html>
<html xmlns:shiro="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8"/>
<title>測(cè)試頁面</title>
</head>
<body>
用戶測(cè)試頁面
<div>
<h3 th:text="${name}"></h3>
</div>
<hr/>
<div shiro:hasPermission="user:add">
進(jìn)入用戶添加功能: <a href="user/add">添加用戶</a><br/>
</div>
<div shiro:hasPermission="user:update">
進(jìn)入用戶更新功能: <a href="user/update">更新用戶</a><br/>
</div>
</body>
</html>