springboot整合Shiro基础实现

shiro

登录拦截ShiroConfig,认证Authentication,授权Authorizing

Shiro安全框架的三大核心:

1.Subject

应用代码的直接交互对象就是Subject,也就是说Shiro对外的核心API就是Subject,Subject代表了当前“用户”,这个用户不是指具体的某一个人,可以说与当前应用交互的任何东西都是Subject,与Subject的所有交互都会委托给SecurityManager来执行,可以理解为Subject只是一个充当门面的,真正的幕后老大是SecurityManager,SecurityManager才是实际的执行者。

2.SecurityManager(安全管理器)
所有与安全有关的操作都会与SecurityManager进行交互,并且SecurityManager管理者所有的Subject,可以看出它才是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMvc中的dispatcherServlet(前端控制器)的角色。

3.Realm
Shiro从Realm获取安全数据(用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法,也需要从Realm获取用户的角色\权限来判断用户是否能进行一系列操作。可以把Realm看作DataSource数据源.

1.导入依赖
//核心依赖
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.4.1</version>
</dependency>
    
//用于页面判断的
<dependency>
  <groupId>com.github.theborakompanioni</groupId>
  <artifactId>thymeleaf-extras-shiro</artifactId>
  <version>2.0.0</version>
</dependency>
2.配置类UserRealm
//继承AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
    @Autowired
    IUserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权");
        //SimpleAuthorizationInfo创建授权信息对象
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //给当前用户授权user:add;在这里添加  相当于给所有用户都赋予user:add权限
        info.addStringPermission("user:add");
        //以下是用数据库给用户赋予权限
        //拿到当前登陆的这个对象,这个对象不是指用户对象,可以说与当前应用交互的任何东西都是Subject;
        Subject subject = SecurityUtils.getSubject();
        //拿到当前登陆的user对象,是认证里面最后一行验证信息里面的user
        User currentUser = (User) subject.getPrincipal();//subject.getPrincipal();获取认证里面的user
        //设置当前用户的权限,数据库读出 前缀必须要 加user: 不然数据库读不到
        info.addStringPermission("user:"+currentUser.getPerms());
        return info;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证");
//        //用户名 密码  数据库中取
//        获取前端的用户和密码
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        User user = userService.querUserByName(userToken.getUsername());//userToken.getUsername()获取前端用户输入的name值  与数据库的name1相比
        if (user == null) {
            return null;  //UnknownAccountException
        }
        //获取当前登陆对象
        Subject subject = SecurityUtils.getSubject();
        //获取Session
        Session session = subject.getSession();
        session.setAttribute("loginUser", user);
        Session session1 = subject.getSession();
        session1.setAttribute("loginname", user.getName());

//          String password11= user.getPassword();
        //密码可以加密:md5,md5盐值加密
        //密码认证  shiro做
//        加盐加密四个参数;用加密算法,加密密码,盐,加密次数
        String pwd = new SimpleHash("md5", user.getPassword(),
                ByteSource.Util.bytes(user.getName()), 5).toString();//加盐加密
        System.out.println("加盐加密5次后" + pwd);
        //返回验证信息1.用户对象 2.数据库的正确密码 3.盐(这里更具用户名加盐) 4.Reiam名字
        //传的是从数据库中获取的password,然后再与token中的password进行对比,匹配上了就通过,匹配不上就报异常。
        return new SimpleAuthenticationInfo(user, user.getPassword(),ByteSource.Util.bytes(user.getName()), getName());

    }
}

3.ShiroConfig
@Configuration
public class ShiroConfig {
    //  ShiroFilterFactoryBean
    //最后一步
    @Bean
    public ShiroFilterFactoryBean ShiroFilterFactoryBean(@Qualifier("manager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean Bean = new ShiroFilterFactoryBean();
        //设置安全管理器  // 关联DefaultWebSecurityManager
        Bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /*     anon:无需认证就可以访问
         *      authc:必须认证了才能访问
         *      user :必须拥有 记住我 功能才能用
         *      perms: 拥有对某个资源的权限才能访问
         *      role:拥有某个角色权限才能访问
         * */
        Map<String, String> filterMap = new LinkedHashMap<>();
        //LinkedHashMap配置拦截的规则,不拦截的放在前面,拦截的放在后面
//        System.out.println("shiro41");
        //授权,正常情况下,没有授权会跳到没授权页面
        filterMap.put("/user/add", "perms[user:add]");//必须要拥有user:add权限才能访问页面
        filterMap.put("/user/update", "perms[user:update]");
        filterMap.put("/**", "authc");//拦截
        //配置记住我或认证通过可以访问的地址
        filterMap.put("/**", "user");
        Bean.setFilterChainDefinitionMap(filterMap);
        //设置拦截后跳转的登陆请求
        Bean.setLoginUrl("/tologin");
        //设置为未授权的请求跳转的页面
        Bean.setUnauthorizedUrl("/noauth");
        return Bean;
    }
    //DefaultWebSecurityManager 核心负责业务操作 
    @Bean(name = "manager")                  //第二步 //@Qualifier("userRealm")是将下面的userRealm关联起来的注释
    public DefaultWebSecurityManager getdefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //关联userRealm
        manager.setRememberMeManager(rememberMeManager());
        manager.setRealm(userRealm);
        return manager;
    }
    //创建realm用户对象  x需要自定义类  第一步
    @Bean(name = "userRealm")    public UserRealm userRealm() {
        return new UserRealm();
    }
     /**
     * cookie管理对象;
     * rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        //System.out.println("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
        return cookieRememberMeManager;
    }
    /**
     * cookie对象;
     * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:
        //setcookie()的第七个参数
        //设为true后,只能通过http访问,javascript无法访问
        //防止xss读取cookie
        simpleCookie.setHttpOnly(true);
        simpleCookie.setPath("/");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(2592000);
        return simpleCookie;
    }
    //整合ShiroDialect,用来整合shiro thymelaf,这个必须要加
    @Bean
    public ShiroDialect getShiroDialect() {
        return new ShiroDialect();
    }
    
}
4.Controller
@Controller
public class Mycontroller {
    @RequestMapping({"/","/index"})
    public String helloshiro(Model model) {
        model.addAttribute("msg", "Hello,shiro");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add() {
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update() {
        return "user/update";
    }

    @RequestMapping("/tologin")
    public String tologin() {
        return "login";
    }

    @RequestMapping("/login")  //用户认证
    public String login(String name, String password, Model model,boolean rememberMe) {
        //获取当前的用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登陆数据
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(name, password,rememberMe);
        try {
            subject.login(usernamePasswordToken);  //执行登陆方法,如果没有异常说明ok了,登陆成功
            return "forward:/";
        } catch (UnknownAccountException e)     //用户不存在
        {
            model.addAttribute("msg", "用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e)      //密码不存在
        {
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }
    //注销页面
    @RequestMapping("/tologout")
    public String tologout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
         return "redirect:/";
    }
    //未授权页面
    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthiruzed() {
        return "未授权无法访问此页面";
    }

}
5.实体类必须实现序列化
/*第一步:在Androidstudio中点击File–Setting–Editor–Inspections–Java–Serialization issues–勾选Serializable class without"serialVersionUID"即可,然后点击OK
第二步:选中实体类类名按住Alt+Enter,选择条目,即可生成serialVersionUID
*/
//必须要实现序列化,否则记住我功能失效
public class User implements Serializable {
    private static final long serialVersionUID = -2085481127044076202L;
    private long id;
    private String name;
    private String password;
    private String perms;
5.前端核心页面
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<h1>首页</h1>
<!--<span style="color: red">${msg}</span>-->
<p th:text="${msg+','+session.loginname}"></p>
<hr/>
<!--从session中判断值-->
<div th:if="${session.loginUser==null}">
    <a th:href="@{/tologin}">登陆</a>
</div>
<!--显示拥有add权限的用户-->
<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">update</a>
</div>
<div th:if="${session.loginUser!=null}">
    <a th:href="@{/tologout}">注销</a>
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值