整合Shiro

HeJin大约 2 分钟Spring全家桶SpringBoot精讲细讲

引入依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.7.1</version>
</dependency>

配置文件

application.yaml

shiro:
  loginUrl: toLogin
  successUrl: /

自定义UserRealm

public class UserRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = (String) principalCollection.getPrimaryPrincipal();

        // 根据用户名查出角色
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(Arrays.asList("admin", "manager"));

        // 根据用户查询权限信息
        info.addStringPermissions(Arrays.asList("user:add", "user:delete"));

        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        String username = token.getUsername();
        // 数据库中查询用户
        User user = userService.findUserByName(username);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        return new SimpleAuthenticationInfo(token.getUsername(), user.getPassword(),getName());
    }
}

config配置类

@Configuration
public class ShiroConfig {

    @Bean
    public Realm getRealm(){
        return new UserRealm();
    }

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        chainDefinition.addPathDefinition("/api/**", "anon");
        chainDefinition.addPathDefinition("/toLogin", "anon");
        chainDefinition.addPathDefinition("/login", "anon");
        chainDefinition.addPathDefinition("/**", "authc");

        return chainDefinition;
    }
    
}

controller层

@RestController
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam String username,
                        @RequestParam String password,
                        @RequestParam(defaultValue = "false") Boolean rememberMe){
        Subject subject = SecurityUtils.getSubject();

        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        token.setRememberMe(rememberMe);

        try {
            subject.login(token);
        } catch (UnknownAccountException uae) {
            return "用户名错误";
        } catch (IncorrectCredentialsException ice) {
            return "密码错误";
        } catch (LockedAccountException lae) {
            return "用户名冻结";
        } catch (AuthenticationException ae) {
            return "其他错误";
        }

        return "success";
    }

}

前端登录页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录</h1>

<form id="loginForm">
    用户名:<input type="text" name="username"> <br>
    密码:<input type="password" name="password"> <br>
    <input type="checkbox" name="rememberMe" value="true"> 记住我<br>

    <input type="button" id="loginBtn" value="登录">
</form>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    $("#loginBtn").click(function () {
        $.post("login", $("#loginForm").serialize(), function (data) {
            console.log(data)
            if (data === "success"){
                location.href = "/"
            }
        })
    })
</script>

</body>
</html>

controller增加接口权限

@Api(tags = "用户的crud操作api")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequiresPermissions("user:query")
    @ApiOperation("分页查询用户")
    @GetMapping("/user")
    public PageBean<User> findAllUser(){
        // 分页
        PageHelper.startPage(1, 2);
        List<User> userList = userService.findAllUser();

        return new PageBean<>(userList);
    }
}

前面UserRealm配置的用户只有user:adduser:delete权限。

info.addStringPermissions(Arrays.asList("user:add", "user:delete"));

/user需要user:query权限,登录之后没有权限访问:

image-20210513163054294
image-20210513163054294

这样在controller层,使用注解@RequiresPermissions控制了后端API接口的权限。

shiro整合thymeleaf

依赖导入

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.7.1</version>
</dependency>

<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

config配置类

@Configuration
public class ShiroConfig {

    /**
     * shiro方言,支持shiro标签
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    @Bean
    public Realm getRealm(){
        return new UserRealm();
    }

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        chainDefinition.addPathDefinition("/api/**", "anon");
        chainDefinition.addPathDefinition("/toLogin", "anon");
        chainDefinition.addPathDefinition("/login", "anon");
        chainDefinition.addPathDefinition("/**", "authc");

        return chainDefinition;
    }

}

html中添加命名空间

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>

<!--用户未登录,显示登录按钮-->
<div shiro:notAuthenticated>
    <a style="font-size: xxx-large; font-weight: bold;" th:href="@{~/toLogin}">登录</a> <br>
</div>

<div shiro:hasPermission="user:delete">
    <span style="font-size: xxx-large; font-weight: bold;">user:delete</span><br>
</div>

<div shiro:hasPermission="user:update">
    <span style="font-size: xxx-large; font-weight: bold;">user:update</span><br>
</div>

<div shiro:hasPermission="user:add">
    <span style="font-size: xxx-large; font-weight: bold;">user:add</span><br>
</div>

<div shiro:hasPermission="user:query">
    <span style="font-size: xxx-large; font-weight: bold;">user:query</span><br>
</div>

</body>
</html>