Nmap RabbitMQ 哨兵模式 tcp syntax tags jq触发点击事件 当前时间减一天 html下拉框默认选中 mysql函数返回结果集 linuxmysql启动命令 python输入输出 python集合操作 python的lambda函数 javasocket通信 java开发教程 java写文件 java文档 批处理if 扫微信二维码诈骗原理 苹果放大镜 c4d文字 jq改变css样式 电脑书籍下载 完美漂移辅助 js动态添加元素 jsp源码下载 平原门下客三千 剑灵龙骨卷轴 黑道圣徒4去马赛克 mmap文件怎么打开 ipad怎么清理内存垃圾 苹果手机怎么微信双开 图片文字提取软件 刻刀工具 vbs代码表白 组合索引 掌门一对一官网下载 iosps腹肌 java游戏高级编程
当前位置: 首页 > 学习教程  > 编程语言

Shiro安全框架(使用总结)

2020/8/31 14:56:19 文章标签:

07Shiro笔记


Shiro 安全框架

1.简介

  • Shiro是一个安全框架,用于解决系统的认证和授权问题,同时提供了会话管理,数据加密,WEB集成,缓存等机制。

  • 身份验证: 即验证用户是不是拥有相应的身份。

    在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,来验证用户的身份:

    principals:身份,即主体的标识属性,可以是用户名、邮箱、手机号等,唯一即可。

    credentials:证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。

    最常见的 principals 和 credentials 组合就是用户名 / 密码。

  • 授权,也叫访问控制,即在应用中控制谁能访问哪些资源。

2.传统认证方式与Shior认证方式的对比

传统认证方式:

img

shiro认证方式:

img

3.Shiro认证流程及架构图

Subject:主体,可以看到主体可以是任何可以与应用交互的 “用户”;

SecurityManager:相当于 SpringMVC 中的 DispatcherServlet ;是 Shiro 的核心;所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。

Authenticator:认证器,负责主体认证的,这是一个扩展点,如果用户觉得 Shiro 默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;

Authorizer:授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

Realm:可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是 JDBC 实现,也可以是 LDAP 实现,或者内存实现等等;由用户提供;注意:Shiro 不知道你的用户 / 权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的 Realm;

SessionManager:如果写过 Servlet 就应该知道 Session 的概念,Session 呢需要有人去管理它的生命周期,这个组件就是 SessionManager;而 Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境、EJB 等环境;所有呢,Shiro 就抽象了一个自己的 Session 来管理主体与应用之间交互的数据;这样的话,比如我们在 Web 环境用,刚开始是一台 Web 服务器;接着又上了台 EJB 服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到 Memcached 服务器);

SessionDAO:DAO 大家都用过,数据访问对象,用于会话的 CRUD,比如我们想把 Session 保存到数据库,那么可以实现自己的 SessionDAO,通过如 JDBC 写到数据库;比如想把 Session 放到 Memcached 中,可以实现自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 进行缓存,以提高性能;

CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于如密码加密 / 解密的。

4.Shiro身份认证的实现

  • 导入依赖

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.5.3</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    
  • 准备用户的身份 / 凭据

SimpleAccountRealm accountRealm = new SimpleAccountRealm();
@BeforeEach
public void before(){
    accountRealm.addAccount("zhangsan","123");
}
  • 测试用例
@Test
    void testAuthentication() {
        //创建安全环境
       DefaultSecurityManager manager = new DefaultSecurityManager();
        //注入域对象
       manager.setRealm(accountRealm);
       SecurityUtils.setSecurityManager(manager);
         //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
       Subject subject = SecurityUtils.getSubject();
       UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");
       try {
        //登录,即身份验证
        subject.login(token);
        } catch (AuthenticationException e) {
            //身份验证失败
        }
       assertEquals(true,subject.isAuthenticated()); //断言用户已经登录
        //退出
       subject.logout();
    }

从如上代码可总结出身份验证的步骤

  1. 收集用户身份 / 凭证,即如用户名 / 密码;
  2. 调用 Subject.login 进行登录,如果失败将得到相应的 AuthenticationException 异常,根据异常提示用户错误信息;否则登录成功;
  3. 最后调用 Subject.logout 进行退出操作。

5.身份认证流程

img

流程如下:

  1. 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;
  2. SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
  3. Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
  4. Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
  5. Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

6.Shiro提供的内置Realm

Realm

Realm:域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。

  • org.apache.shiro.realm.text.IniRealm:[users] 部分指定用户名 / 密码及其角色;[roles] 部分指定角色即权限信息;
[users]
zhang=123
wang=123

此处使用 ini 配置文件,通过 [users] 指定了两个主体:zhang/123、wang/123

  • 测试用例
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
 @Test
    void testAuthentication() {
       DefaultSecurityManager manager = new DefaultSecurityManager();
       manager.setRealm(iniRealm);
       SecurityUtils.setSecurityManager(manager);
       Subject subject = SecurityUtils.getSubject();
       UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
        assertEquals(true,subject.isAuthenticated());
        subject.logout();
    }
  • org.apache.shiro.realm.jdbc.JdbcRealm:通过 sql 查询相应的信息

    JDBC Realm 使用

    1、数据库及依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    <version>5.1.47</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.22</version>
</dependency>

2、到数据库 shiro 下建三张表:users(username/password)、user_roles(role_name/ username)、roles_permissions(permission /role_name)

3、测试用例

JdbcRealm jdbcRealm = new JdbcRealm();
    @BeforeEach
    public void before(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/mydb");
        jdbcRealm.setDataSource(druidDataSource);
        jdbcRealm.setPermissionsLookupEnabled(true);
    }
    @Test
    public void testAuthentication(){
        DefaultSecurityManager manager = new DefaultSecurityManager(jdbcRealm);
        SecurityUtils.setSecurityManager(manager);
        Subject subject = SecurityUtils.getSubject();
        String username;
        String password;
        UsernamePasswordToken token = new UsernamePasswordToken("zs","123");
        subject.login(token);
        assertEquals(true,subject.isAuthenticated());
        subject.checkRole("normal");
        subject.checkPermissions("user:list","user:delete");
        subject.logout();
    }

7.与SpringMvcWeb集成实现认证

Shiro 提供了与 Web 集成的支持,其通过一个 ShiroFilter 入口来拦截需要安全控制的 URL,然后进行相应的控制,ShiroFilter 类似于如 SpringMVC 这种 web 框架的前端控制器,其是安全控制的入口点,判断 URL 是否需要登录 / 权限等工作。

  • 环境准备
    • 导入依赖
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.8.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.5.3</version>
</dependency>
  • web.xml配置
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>
  • 自定义域实现认证
@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();
        User user = userService.findByUsername(username);
        if(user == null) {
            //没找到帐号
            throw new UnknownAccountException();
        }
        if(user.getStatus().equals(SysConstants.LOCKED_STATUS)) {
            //帐号锁定
            throw new LockedAccountException();
        }
        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getUsername(), //用户名
                user.getPassword(), //密码
                ByteSource.Util.bytes(user.getSalt()),
                getName()  //realm name
        );
        return authenticationInfo;
    }
  • springmvc配置Shiro
<!--controller包扫描-->
<context:component-scan base-package="com.woniuxy.sys.controller">
</context:component-scan>
<!--注解驱动-->
<mvc:annotation-driven />
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>
<!--自定义域-->
<bean id="realm" class="com.woniuxy.realm.CustomRealm"></bean>
<!--安全管理器-->
<bean id="securityManager"     			        class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="realm"></property>        
    </bean>
<!--过滤工厂bean-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"></property>
        <property name="unauthorizedUrl" value="403.html"></property>
        <property name="loginUrl" value="login.html"></property>
        <property name="filterChainDefinitions">
            <value>
                /login.html=anon
                /doLogin=anon
                /*=authc
            </value>
        </property>
    </bean>
  • Controller中进行提交认证
@PostMapping("/doLogin")
    public String doLogin(User user){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "fail";
        }
        return "success";
    }

8.实现授权

授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。

主体
主体,即访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权后才允许访问相应的资源。

资源
在应用中用户可以访问的URL,比如访问 JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。

权限
安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如: 访问用户列表页面
查看/新增/修改/删除用户数据(即很多时候都是 CRUD(增查改删)式权限控制)打印文档等

授权流程

img

流程如下:

  1. 首先调用 Subject.isPermitted*/hasRole*接口,其会委托给 SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
  2. Authorizer 是真正的授权者,如果我们调用如 isPermitted(“user:view”),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;
  3. 在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;
  4. Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个 Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如会返回 true,否则返回 false 表示授权失败。
  • 自定义域实现授权
public class CustomRealm extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = principalCollection.getPrimaryPrincipal().toString();
        Set role = new HashSet();
        if(username.equals("hello")){
           role.add("admin");
        }
        Set perms = new HashSet();
        if(username.equals("hello")){
            perms.add("user:list");
            perms.add("user:update");
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(role);
        info.setStringPermissions(perms);
        return info;
    }

    //登录时执行认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String username = authenticationToken.getPrincipal().toString();
        User user = null;
        if(username.equals("hello")){
            user = new User();
            user.setUsername(username);
            user.setPassword("2c28917916001d69078a15b8ab3e5d77");//123
            user.setStatus(1);
        }
        if(user==null){
            throw new UnknownAccountException("账户不存在");
        }
        if(user != null && user.getStatus()==0){
            throw new LockedAccountException("账号已经被锁定");
        }
        //返回认证信息
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),
                ByteSource.Util.bytes("hello"),this.getName());
        return info;
    }
//测试用于获取加密后的密码
//    public static void main(String[] args) {
//        Md5Hash md5Hash = new Md5Hash("123","hello",10);
//        System.out.println(md5Hash);
//    }

}

9.Shiro内置过滤器

内置过滤器 过滤器类 备注
anon org.apache.shiro.web.filter.authc.AnonymousFilter 无参,表示可匿名访问
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter 无参,表示需要认证才能访问
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter 无参,表示需要httpBasic认证才能访问
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 表示用户必需已通过认证,并拥有权限才可以正常发起请求
port org.apache.shiro.web.filter.authz.PortFilter 指定URL端口
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter 根据请求方式来识别,相当于 /admins/user/**=perms[user:get]或perms[user:post] 等等
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 表示用户必需已通过认证,并拥有角色才可以正常发起请求
ssl org.apache.shiro.web.filter.authz.SslFilter 无参,表示需要安全的URL请求,协议为https
user org.apache.shiro.web.filter.authc.UserFilter 表示用户不一定需要通过认证,只要曾被 Shiro 记住过登录状态就可以正常发起 /home 请求
logout org.apache.shiro.web.filter.authc.LogoutFilter 登出

10.Shiro标签

*标签名称* *标签条件(均是显示标签内容)*
shiro:authenticated 已认证通过的用户。不包含已记住的用户,这是与user标签的区别。
shiro:notAuthenticated 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户
shiro:guest 验证当前用户是否为“访客”,即未认证的用户
shiro:user 认证通过或已记住的用户。
shiro:hasAnyRoles 验证当前用户是否属于任意一个角色。sh
shiro:hsaRole 验证当前用户是否属于该角色。
shiro:lacksRole 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。
shiro:hasPermission 验证当前用户是否拥有指定权限
shiro:lacksPermission 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。
shiro:principal 输出当前用户信息,通常为登录帐号信息。

11.Shiro权限注解

Shiro提供了相应的注解用于权限控制,如果使用这些注解就需要使用AOP的功能来进行判断,Shiro提供了Spring AOP集成用于权限注解的解析和验证。

  • 配置依赖
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  • spring-mvc.xml配置文件添加Shiro Spring AOP权限注解的支持:
<aop:config proxy-target-class="true"></aop:config>  
<bean class="  
org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
    <property name="securityManager" ref="securityManager"/>  
</bean>
  • Shiro权限注解

    @RequiresAuthentication 表示当前Subject已经通过login进行了身份验证;即Subject. isAuthenticated()返回true。

    @RequiresRoles 表示当前Subject需要某些角色

    @RequiresPermissions表示当前Subject需要某些权限

  • 当验证失败,其会抛出UnauthorizedException异常,此时可以使用Spring的ExceptionHandler(DefaultExceptionHandler)来进行拦截处理:

@ExceptionHandler({UnauthorizedException.class})  
public ModelAndView processUnauthenticatedException() {  
    ModelAndView mv = new ModelAndView();  
    mv.setViewName("forward:/403.html");  
    return mv;  
}

12.Shiro加密

散列算法

散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如 MD5、SHA 等。一般进行散列时最好提供一个 salt(盐),比如加密密码 “admin”,产生的散列值是 “21232f297a57a5a743894a0e4a801fc3”,可以到一些 md5 解密网站很容易的通过散列值得到密码 “admin”,即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,如用户名和 ID(即盐);这样散列的对象是 “密码 + 用户名 +ID”,这样生成的散列值相对来说更难破解。

String str = "hello";
String salt = "123";
String md5 = new Md5Hash(str, salt).toString();//

如上代码通过盐 “123”MD5 散列 “hello”。另外散列时还可以指定散列次数,如 2 次表示:md5(md5(str)):“new Md5Hash(str, salt, 2).toString()”。

HashedCredentialsMatcher 实现密码验证服务

Shiro 提供了 CredentialsMatcher 的散列实现 HashedCredentialsMatcher,用于密码验证。

SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(),
               user.getPassword(),ByteSource.Util.bytes("盐值"),this.getName());

配置密码匹配器

<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher" id="credentialsMatcher">
        <property name="hashIterations" value="1024"></property>
        <property name="hashAlgorithmName" value="md5"></property>
</bean>
<!--注入密码匹配器-->
<bean id="realm" class="com.woniuxy.realm.CustomRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>

13.缓存

Shiro只提供了一个可以支持具体缓存实现(如:Hazelcast, Ehcache, OSCache, Terracotta, Coherence, GigaSpaces, JBossCache等)的抽象API接口,这样就允许Shiro用户根据自己的需求灵活地选择具体的CacheManager。当然,其实Shiro也自带了一个本地内存CacheManager:org.apache.shiro.cache.MemoryConstrainedCacheManager。

<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager">
</bean>

14.记住我

配置

<bean class="org.apache.shiro.web.mgt.CookieRememberMeManager" id="rememberMeManager">
        <property name="cookie" ref="simpleCookie"></property>
</bean>
<bean class="org.apache.shiro.web.servlet.SimpleCookie" id="simpleCookie">
    <constructor-arg value="rememberMe"></constructor-arg>
    <property name="maxAge" value="180"></property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="realm"></property>
    <property name="rememberMeManager" ref="rememberMeManager"></property>
</bean>

代码实现

UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
token.setRememberMe(true);

要实现记住我功能,必须将管理的model对象实现可序列化(implements Serializable)

在athc过滤配置之前,能够通过记住我访问的页面要配置user过滤器

15.与SpringBoot集成

  • 配置依赖
<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.4.1</version>
</dependency>

<--注意: 这里不需要添加 spring-boot-starter-web 依赖,因为 shiro-spring-boot-web-starter 中已经依赖了 spring-boot-starter-web-->
  • 配置类webmvc

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
    
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/login").setViewName("login");
            registry.addViewController("/index").setViewName("index");
        }
    }
    
  • 自定义域(继承AutorizingRealm)

    public class CustomRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String username = principals.getPrimaryPrincipal().toString();
            //为了方便,就没有去查数据库,角色和权限应该从数据库中查
            //角色
            Set role = new HashSet();
            //权限
            Set perms = new HashSet();
            if(username.equals("hello")){
                System.out.println("hahahahha");
                role.add("admin");
                perms.add("user:list");
            }
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addRoles(role);
            info.addStringPermissions(perms);
            return info;
        }
    
        //验证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
           //获取用户名
            String username = authenticationToken.getPrincipal().toString();
            User user = null;
            if(username.equals("hello")){
                user = new User();
                user.setUsername(username);
                user.setPassword("2c28917916001d69078a15b8ab3e5d77");
                user.setStatus(1);
            }
            if(user == null){
                throw new UnknownAccountException("账号不存在");
            }
            //创建认证信息对象
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),
                    ByteSource.Util.bytes("hello"),this.getName());
            return simpleAuthenticationInfo;
        }
    	
    	//测试获取加密的密码
    //    public static void main(String[] args) {
    //        Md5Hash md5Hash = new Md5Hash("123","hello",10);
    //        System.out.println(md5Hash);
    //    }
    
    }
    
  • Shiro配置

	//自定义域
	//value = "authorizer",有一个系统默认的安全管理器,如果自己不写安全管理器,这个值必须加
	@Bean(value = "authorizer")
    public CustomRealm customRealm(CacheManager cacheManager, CredentialsMatcher credentialsMatcher){
        CustomRealm realm= new CustomRealm();
        realm.setCacheManager(cacheManager);
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }
	//设置过滤的规则
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition shiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
        shiroFilterChainDefinition.addPathDefinition("/login.html","anon");
        shiroFilterChainDefinition.addPathDefinition("/login","anon");
        shiroFilterChainDefinition.addPathDefinition("/doLogin","anon");
        shiroFilterChainDefinition.addPathDefinition("/*.css","anon");
        shiroFilterChainDefinition.addPathDefinition("/**","authc");
        return shiroFilterChainDefinition;
    }
	//密码匹配器
    @Bean
    public HashedCredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashIterations(2);
        matcher.setHashAlgorithmName("md5");
        return matcher;
    }
	//对查询的权限,开启缓存,不用每次去查
    @Bean
    public MemoryConstrainedCacheManager cacheManager(){
        MemoryConstrainedCacheManager manager = new MemoryConstrainedCacheManager();
        return manager;
    }
	 //这个bean是为了支持在Theymeleaf中使用shiro标签,
    // 同时要加依赖thymeleaf-extras-shiro
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
	//记住我功能设置cookie
    @Bean
    public SimpleCookie simpleCookie(){
        SimpleCookie simpleCookie =new SimpleCookie("rememberMe");
          //记住我cookie生效时间,单位秒
        simpleCookie.setMaxAge(180);
        return simpleCookie;
    }
    //设置cookie管理器
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        rememberMeManager.setCookie(simpleCookie());
        return rememberMeManager;
    }
  • UserController

@Controller
public class UserController {

  @ResponseBody
  @PostMapping("/doLogin")
  public String login(User user,String rememberMe){
      //获取主体
      Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
      if(rememberMe!=null && rememberMe.equals("on")){
        token.setRememberMe(true);
      }
      try {
          subject.login(token);
      } catch (AuthenticationException e) {
          e.printStackTrace();
          return "falid";
    }
      return "success";
  }

  @RequestMapping("/delete")
  @ResponseBody
  @RequiresPermissions("user:delete")
  public String delete(){
      System.out.println("delete");
      return "delete";
  }

}


- thymeleaf使用Shiro标签

- 配置依赖

```xml
<dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
</dependency>
  • 注册ShiroDialect
@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}

catch (AuthenticationException e) {
e.printStackTrace();
return “falid”;
}
return “success”;
}

  @RequestMapping("/delete")
  @ResponseBody
  @RequiresPermissions("user:delete")
  public String delete(){
      System.out.println("delete");
      return "delete";
  }

}


- thymeleaf使用Shiro标签

- 配置依赖

```xml
<dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
</dependency>
  • 注册ShiroDialect
@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}
  • Html导入命名空间 : xmlns:shiro=”http://www.pollix.at/thymeleaf/shiro"

本文链接: http://www.dtmao.cc/news_show_150308.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?