springboot整合mybatis-plus,shiro,以及前后端分离
引入依赖
<dependencies>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
dao,entity,service
UserServiceImpl :根据用户名查询用户信息
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserDao userDao;
public User selectByUsername(String username) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
return userDao.selectOne(wrapper);
}
}
PermissionServiceImpl :根据用户id查询用户所有权限
@Service
public class PermissionServiceImpl implements PermissionService {
@Resource
private PermissionDao permissionDao;
@Override
public List<String> findPermissByUserId(Integer userid) {
return permissionDao.findPermissByUserId(userid);
}
}
UserDao层:没有方法·,使用mybatis-puls提供的selectone()方法
PermissionDao:
public interface PermissionDao {
List<String> findPermissByUserId(Integer userid);
}
整合shiro
(1)创建一个配置类
@Configuration
public class ShiroConfig {
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(Realm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
// IOC控制反转 DI依赖注入
@Bean(value = "myRealm")
public Realm getRealm(CredentialsMatcher credentialsMatcher) {
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher);
return myRealm;
}
@Bean(value = "credentialsMatcher")
public CredentialsMatcher getCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashIterations(1024);
credentialsMatcher.setHashAlgorithmName("MD5");
return credentialsMatcher;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setSuccessUrl("/success.html");
shiroFilterFactoryBean.setLoginUrl("/tologin");
//重点 shiro 不配置登录页面 会默认跳转到login.jsp
HashMap<String, String> map = new HashMap<>();
map.put("/index.html", "anon");
map.put("/static/**", "anon");
map.put("/login", "anon");
map.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//未登录才会走这个过滤器
HashMap<String, Filter> loginFilter = new HashMap<>();
loginFilter.put("authc",new LoginFilter());
shiroFilterFactoryBean.setFilters(loginFilter);
return shiroFilterFactoryBean;
}
// 注册filter组件
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setName("shiroFilter");
filterRegistrationBean.setFilter(new DelegatingFilterProxy());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
//使用shiro标签库可以在thymeleaf使用
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
(2)前台页面login ,success页面,unPermission.html没有权限页面
(3)realm认证的代码
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获得账户名
String username = token.getPrincipal().toString();
// 根据账户名查询用户信息
User user = userService.selectByUsername(username);
if (user != null) {
// 获得盐
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
//这第一个传的参数 会在doGetAuthorizationInfo方法中的principals对象 principals.getPrimaryPrincipal() 取到
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), salt, this.getName());
return info;
}
return null;
}
realm授权的代码
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal(); //获取用户的信息
// 根据用户id查询所有权限
List<String> permissions = permissionService.findPermissByUserId(user.getUserid());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if (permissions.size()>0){
// 绑定权限
info.addStringPermissions(permissions);
return info;
}
return null;
}
(4)success页面
①使用shiro需要引入shiro标签库
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
②在需要显示权限的地方外面加入
@RequiresPermissions(“user:query”)
其中,name=“user:query”
eg:
<shiro:hasPermission name=“user:query”>
查询所有用户
</shiro:hasPermission>
具体代码实现:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入shiro标签库--%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
登录成功<br>
<shiro:hasPermission name="user:query">
<a href="/user/query">查询所有用户</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:update">
<a href="/user/update">修改用户</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete">
<a href="/user/delete">删除用户</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:insert">
<a href="/user/insert">添加用户</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="user:export">
<a href="/user/export">导出用户</a><br>
</shiro:hasPermission>
</body>
</html>
③默认thymeleaf不支持shiro标签库。使用如下方式来解决
<!--thymeleaf支持shiro的依赖-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
④config配置类中:
//使shiro标签库可以在thymeleaf中使用
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
注意:不在config中配置就全部显示,加上config配置。这样就会显示应有的权限,没有的权限就不会显示。
(5)userController层的权限
需要使用这个权限注解 前台的name中:name=“user:insert”@RequiresPermissions(“user:insert”)
@RequiresPermissions("user:insert")
@GetMapping("insert")
public String insert() {
return "user:insert";
}
@RequiresPermissions("user:export")
@GetMapping("export")
public String export() {
return "user:export";
}
前后端分离
- 登陆成功后要返回json数据
- 没有权限—返回一个json
- 如果未登陆直接返回主界面----json格式。
登陆成功后要返回json数据
controller层
@PostMapping("/login")
public CommonResult login(String username, String userpwd){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(username,userpwd);
try {
// 登录成功就走视图解析器到success
subject.login(token);
Object user = subject.getPrincipal();
return new CommonResult(2000,"登录成功",user);
}catch (Exception e){
// 登录失败就走视图解析器到登陆页面
return new CommonResult(5000,"登录成功",null);
}
}
CommonResult 类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult {
private Integer code;
private String msg;
private Object data;
}
没有权限—返回一个json
没有权限时会报异常UnauthorizedException
进行封装一个异常处理类
//返回到前台是一个json数据
@RestControllerAdvice
public class MyHandlerException {
//没有权限时加载这个页面
//UnauthorizedException
@ExceptionHandler(value = UnauthorizedException.class)
public CommonResult unauthenticatedException() {
return new CommonResult(5001,"权限不足",null);
}
}
如果未登陆直接返回主界面----json格式(1)
如果未登陆直接返回主界面----json格式(2)
需要在shiroConfig中配置 shiroFilterFactoryBean方法添加配置
//未登录才会走这个过滤器
HashMap<String, Filter> loginFilter = new HashMap<>();
loginFilter.put("authc",new LoginFilter());
shiroFilterFactoryBean.setFilters(loginFilter);
自定义的filter
public class LoginFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
// 设置编码格式
response.setContentType("application/json;charset=utf-8");
CommonResult commonResult = new CommonResult(5003, "权限不足", null);
PrintWriter writer = response.getWriter();
writer.print(JSON.toJSONString(commonResult));
return false;
}
}