记录springboot整合shiro和thymeleaf实现权限控制
1:导入依赖jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2:编写UserRealm配置类类继承了AuthorizingReaml并重写了其中的两个方法
(1)AuthorizationInfo :
授权方法:SimpleAuthorizationInfo 通过这个凭证获取到认证之后的账号密码
(2)AuthenticationInfo :
认证方法:authenticationToken会封装登录的一些信息(用户名、密码)并且由Subject带到此处,
//User subject = (User) SecurityUtils.getSubject();
User user = (User) principalCollection.getPrimaryPrincipal();
上述两个方法都可以获取到认证之后的信息,就是认证SimpleAuthenticationInfo凭证里面存储的值
通过SimpleAuthorizationInfo来存储该认证之后的用户的角色集合和权限集合。
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
@Autowired
RoleService roleService;
@Autowired
PermissionService permissionService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("========开始权限验证========");
//String username = (String) SecurityUtils.getSubject().getPrincipal();
//User subject = (User) SecurityUtils.getSubject();
User user = (User) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//查询登录用户所拥有的角色,并添加角色
List<Role> roles = roleService.getAllRolesByUid(user.getId());
for (Role role : roles) {
info.addRole(role.getName());
System.out.println(role);
List<Permission> permissions = permissionService.getAllPermissionByUid(user.getId());
//查询登录用户所拥有的权限,并添加权限
for (Permission permission : permissions) {
System.out.println(permission);
info.addStringPermission(permission.getName());
}
}
return info;
}
//重写验证身份的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("========开始身份验证========");
String username = (String) authenticationToken.getPrincipal();
String userpassword = new String((char[]) authenticationToken.getCredentials());
User user = userService.getOne(new QueryWrapper<User>()
.eq("id",username)
.eq("password",userpassword));
System.out.println(user);
if (user == null) {
throw new AccountException("用户名或密码错误");
}
return new SimpleAuthenticationInfo(user, userpassword, getName());
}
}
3:编写shiro的配置类
(容易出错的地方):springboot默认有一个securitymanager的组件,所以我们通过sessionsecuritymanager来代替。
@Configuration
public class ShiroConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
logger.info("启动shiroFilter--时间是:" + new Date());
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//这里设置没有登录时,跳转界面
shiroFilterFactoryBean.setLoginUrl("/");
//这里是没有授权时,跳转的界面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuthc");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/doLogin", "anon");
filterChainDefinitionMap.put("/jquery-3.4.1/**", "anon");
filterChainDefinitionMap.put("/layui/**", "anon");
filterChainDefinitionMap.put("/plugins/**", "anon");
filterChainDefinitionMap.put("/FinishTask/Performance","perms[performance:list]");
//filterChainDefinitionMap.put("/student/delete/**","perms[delete]");
//filterChainDefinitionMap.put("/student/toadd/**", "perms[create]");
//filterChainDefinitionMap.put("/user/delete/**","perms[delete]");
//filterChainDefinitionMap.put("/user/toadd/**", "perms[create]");
//filterChainDefinitionMap.put("/student/toeditstudent/**", "perms[update]");
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 配置shiro的生命周期
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean(name = "securityManager")
public SessionsSecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
defaultSecurityManager.setRealm(userRealm());
return defaultSecurityManager;
}
@Bean("userRealm")
public UserRealm userRealm() {
UserRealm userRealm = new UserRealm();
return userRealm;
}
//注解
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
sourceAdvisor.setSecurityManager(securityManager);
return sourceAdvisor;
}
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
//配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException","404");
simpleMappingExceptionResolver.setExceptionMappings(mappings); // None by default
simpleMappingExceptionResolver.setDefaultErrorView("404"); // No default
simpleMappingExceptionResolver.setExceptionAttribute("ex"); // Default is "exception"
return simpleMappingExceptionResolver;
}
}
4:登录的requestMapping
usernamePasswordToken的作用是存储用户的账号和密码,subject.login(usernamePasswordToken);执行登录即可。
@RequestMapping("/doLogin")
public String doLogin(String username , String password ,
Model model, HttpSession session){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
try {
subject.login(usernamePasswordToken);
} catch (UnknownAccountException uae) {
model.addAttribute("msg","未知账户");
return "login";
} catch (IncorrectCredentialsException ice) {
model.addAttribute("msg","*密码不正确~");
return "login";
} catch (LockedAccountException lae) {
model.addAttribute("msg","*账户已锁定~");
return "login";
} catch (ExcessiveAttemptsException eae) {
model.addAttribute("msg","*用户名或密码错误次数过多~");
return "login";
} catch (AuthenticationException ae) {
model.addAttribute("msg","*用户名或密码不正确~");
return "login";
}
if (subject.isAuthenticated()) {
User user = userMapper.selectOne(new QueryWrapper<User>()
.eq("id",username)
.eq("password",password));
session.setAttribute("user",user);
return "index";
} else {
usernamePasswordToken.clear();
model.addAttribute("msg","*未知账户~");
return "login";
}
}
5:和前端html页面进行整合
在需要有权限的地方使用
<shiro:hasPermission name="performance:list">...</shiro:hasPermission>

浙公网安备 33010602011771号