SpringBoot整合Shiro

SpringBoot整合Shiro

Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等.shiro不依赖任何容器,可以直接运行在javase和javaee中


shiro核心组件
我们会给角色赋予权限,给用户赋予角色
1、UsernamePasswordToken,Shiro 用来封装用户登录信息,使用用户的登录信息来创建令牌 Token。
2、SecurityManager,Shiro 的核心部分,负责安全认证和授权。
3、Suject,Shiro 的一个抽象概念,包含了用户信息。
4、Realm,开发者自定义的模块,根据项目的需求,验证和授权的逻辑全部写在 Realm 中。
5、AuthenticationInfo,用户的角色信息集合,认证时使用。
6、AuthorzationInfo,角色的权限信息集合,授权时使用。
7、DefaultWebSecurityManager,安全管理器,开发者自定义的 Realm 需要注入到 DefaultWebSecurityManager 进行管理才能生效。
8、ShiroFilterFactoryBean,过滤器工厂,Shiro 的基本运行机制是开发者定制规则,Shiro 去执行,具体的执行操作就是由 ShiroFilterFactoryBean 创建的一个个 Filter 对象来完成。

shiro入门与SpringBoot整合

创建SpringBoot项目,导入依赖

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.5.3</version>
    </dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.20</version>
</dependency>
 
 
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1.tmp</version>
</dependency>

根据数据库字段创建实体类

@Data
public class Account {
    private Integer id;
    private String username;
    private String password;
    private String perms;
    private String role;
}

根据实体类创建接口

@Mapper
public interface AccountMapper extends BaseMapper<Account> {
}

配置mysql和mybatisplus

#mysql
spring.datasource.url=jdbc:mysql://localhost:3306/****?useUnicode=true&characterEncoding=utf8
spring.datasource.username=****
spring.datasource.password=****
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#mybatis-plus
mybatis-plus.mapper-locations=classpath:com/mht/springbootmybatisplus/mapper/xml/*.xml
mybatis-plus.type-aliases-package=com.mht.springbootmybatisplus.entity
#关闭驼峰命名法
mybatis-plus.configuration.map-underscore-to-camel-case: false
#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

编写service层

@Service
public interface AccountService {
    public Account findByUsername(String username);
}

Impl

public class AccountServiceImpl implements AccountService {
 
 
    @Autowired
    private AccountMapper accountMapper;
 
 
    @Override
    public Account findByUsername(String username) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username",username);
        return accountMapper.selectOne(wrapper);
    }
}
在shiro中用户认证

编写MyRealm 继承AuthorizingRealm

前端返回的用户密码都封装道token中了,通过token验证用户是否存在,不存在直接返回一个null;

SimpleAuthenticationInfo(account,account.getPassword(),getName());直接把数据丢进去,就会使account.getPassword()和token 中前端返回的密码经行验证

public class MyRealm extends AuthorizingRealm {
 
 
    @Autowired
    private AccountService accountService;
 
 
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
 
 
    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //token封转了前端传来的用户名和密码
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //用户名验证
        Account account = accountService.findByUsername(token.getUsername());
        
        //用户名不为空就传入到SimpleAuthenticationInfo中验证密码
        if(account != null){
            return new 
                //account.getPassword()是正确的通过用户名查询到的密码
                SimpleAuthenticationInfo(account,account.getPassword(),getName());
        }
        return null;
    }
}

因为这些东西都需要进行配置,所以需要编写配置类ShiroConfig

编写配置类ShiroConfig
@Configuration
public class ShiroConfig {
 
 
    // 过滤器工厂	实际去执行的bean
    // 通过@Qualifier("manager") DefaultWebSecurityManager manager拿到默认的Web安全管理器	
    // 设置我们自定义的安全管理器
    @Bean
    public ShiroFilterFactoryBean filterFactoryBean(@Qualifier("manager") DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(manager);
        return factoryBean;
    }
 
 
 

	// 2.默认的Web安全管理器	
    // 通过@Qualifier("myRealm") MyRealm myRealm	从ioc中取出myRealm
    // 并且吧自定义的realm配置进去
    @Bean
    public DefaultWebSecurityManager manager(@Qualifier("myRealm") MyRealm myRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(myRealm);
        return manager;
    }
 
 //1.先把MyRealm注入到spring中
    @Bean
    public MyRealm myRealm(){
        return new MyRealm();
    }
}
编写用户认证和授权规则

认证过滤器:
anon:无需认证即可访问,游客身份。
authc:必须认证(登录)才能访问。
authcBasic:需要通过 httpBasic 认证。
user:不一定已通过认证,只要是曾经被 Shiro 记住过登录状态的用户就可以正常发起请求,比如 rememberMe。

授权过滤器:
perms:必须拥有对某个资源的访问权限(授权)才能访问。
role:必须拥有某个角色权限才能访问。
port:请求的端口必须为指定值才可以访问。
rest:请求必须是 RESTful,method 为 post、get、delete、put。
ssl:必须是安全的 URL 请求,协议为 HTTPS。

编写过滤器工厂ShiroFilterFactoryBean

@Bean
public ShiroFilterFactoryBean filterFactoryBean(@Qualifier("manager") DefaultWebSecurityManager manager){
    ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
    factoryBean.setSecurityManager(manager);
    //权限设置
    Map<String,String> map = new HashMap<>();
    map.put("/main","authc");	//访问mian必须登录状态
    map.put("/manage","perms[manage]");
    map.put("/administrator","roles[administrator]");
    factoryBean.setFilterChainDefinitionMap(map);
    //设置登录页面
    factoryBean.setLoginUrl("/login");
    //未授权页面
    factoryBean.setUnauthorizedUrl("/unauth");
    return factoryBean;
}

编写Controller层接口

根据不同的异常返回不同的信息

@Controller
public class MyController {
 
 
    @PostMapping("/login")
    public String login(String username, String password, Model model){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            // 
            subject.login(token);
            return "index";
        } catch (UnknownAccountException e) {
            model.addAttribute("msg","用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }
 
 	//未授权页面返回信息
    @RequestMapping("/unauth")
    @ResponseBody
    public String unauth(){
        return "未授权没有访问权限";
    }
}
编写前端页面

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>

<a href="/main.html">main</a>
<a href="/manage.html">manage</a>
<a href="/administrator.html">administrator</a>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登陆
<form action="/login" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td>
                <input type="text" name="username">
            </td>
        </tr>

        <tr>
            <td>密码:</td>
            <td>
                <input type="password" name="password">
            </td>
        </tr>

        <tr>
            <td>
                <input type="submit" value="登陆">
            </td>
        </tr>
    </table>
</form>
</body>
</html>

main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head>
<body>
main
</body>
</html>

manage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>manage</title>
</head>
<body>
manage
</body>
</html>

administrator.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>administrator</title>
</head>
<body>
administrator
</body>
</html>

这时候登陆测试,这时候只要登陆了,就能访问main,但是其他的无法访问;是因为我们没有授权

编写授权doGetAuthorizationInfo()
·@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    //获取当前登录对象
    Subject subject = SecurityUtils.getSubject();
    Account account = (Account) subject.getPrincipal();
 
 
    //设置角色
    Set<String> roles = new HashSet<>();
    roles.add(account.getRole());
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
 
 
    //设置权限
    info.addStringPermission(account.getPerms());
    return info;
}

数据库中用户信息如下

img

这时候我们使用ls登陆就能访问main和manage,使用ww登陆就能全部访问

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值