shiro的認證和授權控制頁面
阿新 • • 發佈:2020-12-22
環境
- springboot
- shiro
簡介
我這裡只講一個shiro簡單的demo,原理大家可以深入學習其他的文章
實現過程
1、首先需要匯入pom依賴
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3< /version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
< groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache< /artifactId>
<version>1.2.3</version>
</dependency>
<!--thymeleaf依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!--shiro整合thymeleaf-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2、寫配置類
@Configuration
public class ShiroConfig {
//3. shiroFilterfactaryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);//設定安全管理器
shiroFilterFactoryBean.setLoginUrl("/login");//沒有認證後跳到的頁面
/**
* shiro的內建過濾器
anon:無需認證就可以訪問 預設
authc:必須認證了才能訪問
user:必須擁有記住我功能才能訪問
perms:必須擁有對某個的許可權才能訪問
role:擁有某個角色許可權才能訪問
*/
//新增shiro的內建過濾器 設定要攔截的url
Map<String,String> filterChainDefinitionMap=new LinkedHashMap<>();//攔截
/index路徑請求必須認證才能訪問 filterChainDefinitionMap.put("/index","authc");//
//不需要認證
filterChainDefinitionMap.put("/login.html","anon");
filterChainDefinitionMap.put("/hello","authc");
//設定登出的url
filterChainDefinitionMap.put("/logout","logout");
filterChainDefinitionMap.put("/add.html","authc");
filterChainDefinitionMap.put("/404.html","authc");
//filterChainDefinitionMap.put("/del","authc");//del必須認證才能訪問
// filterChainDefinitionMap.put("user/**","authc");//支援萬用字元
//授權
//使用者為guest才有許可權訪問add.html頁面
filterChainDefinitionMap.put("/add.html","roles[guest]");
//擁有user:add許可權才可以訪問 filterChainDefinitionMap.put("/404.html","perms[user:add]");
//沒有這個user:delete許可權的會被攔截下來 //filterChainDefinitionMap.put("/del","perms[user:delete]");
//未授權的跳轉的url
shiroFilterFactoryBean.setUnauthorizedUrl("/login");
/*設定登入成功之後跳轉的頁面,這個頁面是一個附加請求,也就是說如果登入成功之後沒有設定跳轉頁面他才會跳轉到這個頁面*/
//shiroFilterFactoryBean.setSuccessUrl("/success.html");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);//把設定好的過濾設定到ShiroFilterFactoryBean
return shiroFilterFactoryBean;
}
//2. DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//關聯realm物件 userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 建立realm物件 自定義的·類
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合shiroDialect:用來整合shiro-thymeleaf
@Bean
public ShiroDialect getshiroDialect(){
return new ShiroDialect();
}
/**
* 下面兩個配置是為了讓shiro的註解有效,
* 如果不滿足註解會自動拋異常,所以這個時候就需要寫全域性異常處理
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
return authorizationAttributeSourceAdvisor;
}
}
3、認證與授權
public class UserRealm extends AuthorizingRealm {
@Autowired(required = false)
private UserMapper userMapper;
@Autowired
private UserService userService;
/**
* 授權:授權的主要目的就是根據認證資料提取到使用者的許可權資訊
* principalCollection:包含了所有已經認證的安全資料
* AuthorizationInfo:授權資料
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//獲取身份資訊
String name= (String) principalCollection.getPrimaryPrincipal();
//根據身份資訊從資料庫中查詢角色和許可權資料
User user=userService.queryByName(name);
//這裡使用靜態資料模擬
Set<String> permissions=new HashSet<>();
permissions.add(user.getPermission());
Set<String> roles=new HashSet<>();
roles.add(user.getRole());
//構造返回
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//設定許可權集合
info.setStringPermissions(permissions);
//設定角色集合
info.setRoles(roles);
return info;
}
/**
* 認證
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加這一步的目的是在Post請求的時候會先進認證,然後在到請求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//獲取使用者資訊
String name = authenticationToken.getPrincipal().toString();
User user = userService.queryByName(name);
if (user == null) {
//這裡返回後會報出對應異常
return null;
} else {
//這裡驗證authenticationToken和simpleAuthenticationInfo的資訊
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
}
4、實體類
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@TableField("id")
private Long Id;
private String name;
private Integer age;
private String email;
private String password;
private String role;
private String permission;
}
5、mapper類
/**
* 直接繼承 BaseMapper,這是 mybatis-plus 封裝好的類。
*/
public interface UserMapper extends BaseMapper<User> {
User queryByName(String username);
}
6、業務類
public interface UserService {
User queryByName(String username);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired(required = false)
private UserMapper userMapper;
@Override
public User queryByName(String username) {
QueryWrapper wrapper=new QueryWrapper();
wrapper.eq("name",username);
User user=userMapper.selectOne(wrapper);
return user;
}
}
7、控制類
@Controller
public class UserController {
@Autowired(required = false)
RoleService roleService;
@RequestMapping("/tologin")
public String tologin(User user){
//獲取主體
Subject subject = SecurityUtils.getSubject();
try {
subject.login(new UsernamePasswordToken(user.getName(), user.getPassword()));
System.out.println(subject.hasRole("role1"));
System.out.println(subject.isPermitted("user:save"));
} catch (UnknownAccountException e) {
System.out.println("賬號不存在");
return "login";
} catch (AccountException e) {
System.out.println("賬號或密碼不正確");
return "login";
} catch (IncorrectCredentialsException e) {
System.out.println("賬號或密碼不正確");
return "login";
}
return "index";
}
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping("/index")
public String index(){
return "index";
}
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "hello";
}
/**
* 登出成功之後會預設跳轉的index.html頁面,所以我這樣寫是無效的
* 可以自己去修改跳轉的頁面
* @return
*/
@RequestMapping("/logout")
public String logout(){
return "login";
}
@RequestMapping("/role")
@RequiresAuthentication
@ResponseBody
public String testRole(){
return "role";
}
}
8、頁面
404.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
404
</body>
</html>
add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新增</title>
</head>
<body>
新增
</body>
</html>
delete.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>刪除</title>
</head>
<body>
刪除
</body>
</html>
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
首頁
</body>
</html>
login.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登入</title>
</head>
<body>
<form th:action="/tologin">
<input type="text" name="name" value="">
<input type="password" name="password" value="">
<input type="submit" value="登入">
</form>
</body>
</html>
需要認證的頁面都會先跳轉到登入頁面,登入成功之後才可以訪問其他頁面