Shrio_Shrio集成Spring&Authentication身份认证&Authorizing授权

1 Shiro简介

1.1 Shiro介绍

Apache Shiro是一个强大且易用的Java安全框架,有身份验证授权密码学会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
Spring security 重量级安全框架
Apache Shiro轻量级安全框架

1.2 Shiro功能

在这里插入图片描述
Shiro 开发团队称为“应用程序的四大基石” ——身份验证,授权,会话管理和加密作为其目标
Authentication(身份认证):这是一个证明用户是他们所说的他们是谁的行为
Authorization(授权):访问控制的过程,也就是绝对“谁”去访问“什么”权限
Session Management:管理用户特定的会话,即使在非 Web 或 EJB 应用程序。
Cryptography:通过使用加密算法保持数据安全同时易于使用。
Web Support: Shiro 的 web 支持的 API 能够轻松地帮助保护 Web 应用程序。
Caching:缓存是 Apache Shiro 中的第一层公民,来确保安全操作快速而又高效。
Concurrency: Apache Shiro 利用它的并发特性来支持多线程应用程序。
Testing:测试支持的存在来帮助你编写单元测试和集成测试,并确保你的能够如预期的一样安全。
“Run As”:一个允许用户假设为另一个用户身份(如果允许)的功能,有时候在管理脚本很有用。
“Remember Me”:在会话中记住用户的身份,所以他们只需要在强制时候登录。

2 Shiro入门

2.1 配置shiro.ini模式

导包

<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

测试 底层默认找IniRealm

2.2 自定义的Realm的模式

//自定义Realm
public class MyRealm extends AuthorizingRealm {
    //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //得到主体 --用户名
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        //根据用户名去拿到权限 -- 从数据库查询
        Set<String> roles = getRoleByPrincipal(primaryPrincipal);
        //根据用户名去拿到角色 - 从数据库查询
        Set<String> permissions = getPermissionByPrincipal(primaryPrincipal);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //设置角色
        simpleAuthorizationInfo.setRoles(roles);
        //设置权限
        simpleAuthorizationInfo.setStringPermissions(permissions);
        //返回对象
        return simpleAuthorizationInfo;
    }
    //通过用户拿到角色
    private Set<String> getRoleByPrincipal(String primaryPrincipal) {
        Set<String> roles = new HashSet<String>();
        if("haoge".equals(primaryPrincipal)){
            roles.add("admin");
            return roles;
        }else{
            return null;
        }
    }
    //通过用户拿到操作的权限
    private Set<String> getPermissionByPrincipal(String primaryPrincipal) {
        Set<String> permissions = new HashSet<String>();
        if("haoge".equals(primaryPrincipal)){
            permissions.add("driver:*");
            return permissions;
        }else{
            return null;
        }
    }
    //身份认证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //得到令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //主体
        Object principal = token.getPrincipal();
        System.out.println(principal);
        //获取用户名 zhangsan
        String username = token.getUsername();
        System.out.println(username);
        //通过用户名 去数据库查询数据 -- 查询用户的信息
       // 没有加密返回 String dbpwd= getPwdByUsername(username);
        String md5Pwd = getMD5PwdByUsername(username);
        //处理用户名问题 用户名是否存在的问题
        if(md5Pwd==null){
            //用户不存在
            return null;
        }
        //ByteSource
        ByteSource salt = ByteSource.Util.bytes("itsource");
        //下面进行密码的比对  shiro 底层它会自动进行比对 -- 处理密码问题
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, md5Pwd,salt, getName());
        return simpleAuthenticationInfo;
    }
    //通过用户名去拿到密码
    public String getPwdByUsername(String username){
        if("haoge".equals(username)){
            return "123";
        }else{
            return null;
        }
    }
    //加密返回密码
    public String getMD5PwdByUsername(String username){
        if("haoge".equals(username)){
            return "d5a3fedf6c59c2ecbe7f7a6c1a22da37";
        }else{
            return null;
        }
    }
    public static void main(String[] args) {
        //MD5 本身是不可破解 ..不可逆  网上看到破解方式 都是穷举把
        //(1)普通加密+202cb962ac59075b964b07152d234b70 -123
        SimpleHash simpleHash = new SimpleHash("MD5","123" );
        //(2)加密+加次数
        SimpleHash simpleHash1 = new SimpleHash("MD5","123",null,10 );
        //5371007260db2b98e3f7402395c45f28
        //(3)加密123 加盐 + itsource +加次数 --d5a3fedf6c59c2ecbe7f7a6c1a22da37 -- 最安全
        SimpleHash simpleHash2 = new SimpleHash("MD5","123","itsource",10 );
        System.out.println(simpleHash.toString());
        System.out.println(simpleHash1.toString());
        System.out.println(simpleHash2.toString());
    }
}

测试

3 Shiro整合Spring

3.1 导入jar包

<!-- shiro的支持包 -->
 <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.4.0</version>
    <type>pom</type>
</dependency>
  <!-- shiro与Spring的集成包 -->
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
  </dependency>

3.2 配置过滤器

通过代理过滤器 找shiro里面真实过滤器

<!--这是一个代理过滤器,它会到spring的配置中找一个名称相同的真实过滤器-->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3.3 配置shiro的 ApplicationContext-shiro.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置核心的安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm" />
    </bean>

    <bean id="myRealm" class="cn.itsource.shiro.MyRealm">
        <property name="credentialsMatcher">
            <!--设置加密匹配方案-->
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!-- 编码的方式使用:md5 -->
                <property name="hashAlgorithmName" value="MD5"/>
                <!-- 编码的次数:10 -->
                <property name="hashIterations" value="10"/>
            </bean>
        </property>
    </bean>

    <!-- 3.lifecycleBeanPostProcessor:可以自动调用在Spring Ioc窗口中 Shiro bean的生成周期方法 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    <!-- 4.启动ioc容器中使用 shiro的注解,但是必需配置在Spring Ioc容器中Shiro bean的生成周期方法 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <!--真实过滤器  id必须是web.xml里面配的名字-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <!--认证没有成功跳转的页面-->
        <property name="loginUrl" value="/s/login.jsp" />
        <!--登录成功 进入的页面-->
        <property name="successUrl" value="/s/main.jsp" />
        <!--没有权限  进入的页面-->
        <property name="unauthorizedUrl" value="/s/unauthorized.jsp" />
        <!--
            配置放行和拦截的请求
            anon:不需要登录也可以访问相应的权限
            authc:需要权限才能访问
            /** :所有文件及其子文件
        -->
        <!--<property name="filterChainDefinitions">
            <value>
                /s/login.jsp=anon
                /login=anon
                &lt;!&ndash;对资源进行权限控制,要控制的资源都应该从数据库查出,现在咱们先写死&ndash;&gt;
                /s/permission.jsp = perms[user:*]
                /**=authc
            </value>
        </property>-->
        <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap" />
    </bean>
    <!--
        配置bean
        factory-bean:具体应用bean
        factory-method:调用里面的方法
    -->
    <bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="createFilterChainDefinitionMap" />

    <bean id="filterChainDefinitionMapBuilder" class="cn.itsource.shiro.FilterChainDefinitionMapBuilder" />
</beans>

3.4 注意:在启动服务的时候,引用配置文件

<!--引入配置文件-->
<import resource="ApplicationContext-shiro.xml" />

4 完成shiro的认证和授权

4.1 认证

前台:
准备登陆页面

后台:
创建Controller /LoginController

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(String username,String pwd){
        //主体
        Subject subject = SecurityUtils.getSubject();
        //判断该主体是否已经认证过
        if (!subject.isAuthenticated()) {
            try {
                UsernamePasswordToken token = new UsernamePasswordToken(username, pwd);
                subject.login(token);
            }catch (UnknownAccountException uae) {
                System.out.println("账号不存在");
            } catch (IncorrectCredentialsException ice) {
                System.out.println("密码有误");
            } catch (LockedAccountException lae) {
                System.out.println("这个账号已经被锁定");
            }catch (AuthenticationException ae) {
                System.out.println("其他认证错误");
            }
        }
        return "redirect:/s/main.jsp";
    }
}

4.2 登陆方法login(包含username,password)

4.3 身份认证

//身份认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    String username = (String) authenticationToken.getPrincipal();
    UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    String username1 = token.getUsername();
    String pwd = getPwdByUsername(username1);
    if (pwd == null){
        return null;
    }
    //在这里加盐值需一个ByteSource对象,而Shiro提供了一个ByteSource对象给咱们
    ByteSource salt = ByteSource.Util.bytes("itsource");
    //密码比对
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, pwd,salt,getName());
    return authenticationInfo;
}
private String getPwdByUsername(String username){
    if ("aaa".equals(username)){
        return "d5a3fedf6c59c2ecbe7f7a6c1a22da37";
    }else {
        return null;
    }
}

输入正确,完成登录,否则登录失败,返回登录界面

4.4 授权

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    //当前用户的权限你弄出来 给 shiro
    //得到主体用户
    String username = (String) principalCollection.getPrimaryPrincipal();
    //根据用户  从数据库拿到权限  加入到shiro里面去
    Set<String> permissions = new HashSet<>();
    if(username.equals("aaa")){
        permissions.add("user:*");
        permissions.add("employee:*");

    }
    SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    simpleAuthorizationInfo.addStringPermissions(permissions);
    //返回权限里面  判断
    return simpleAuthorizationInfo;
}

5 配置放行和拦截的请求,控制的资源从数据库查出

5.1 ApplicationContext-shiro.xml配置

<!--真实过滤器  id必须是web.xml里面配的名字-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <!--认证没有成功跳转的页面-->
    <property name="loginUrl" value="/s/login.jsp" />
    <!--登录成功 进入的页面-->
    <property name="successUrl" value="/s/main.jsp" />
    <!--没有权限  进入的页面-->
    <property name="unauthorizedUrl" value="/s/unauthorized.jsp" />
    <!--
        配置放行和拦截的请求
        anon:不需要登录也可以访问相应的权限
        authc:需要权限才能访问
        /** :所有文件及其子文件
    -->
    <!--<property name="filterChainDefinitions">
        <value>
            /s/login.jsp=anon
            /login=anon
                &lt;!&ndash;对资源进行权限控制,要控制的资源都应该从数据库查出
            /s/permission.jsp = perms[user:*]
            /**=authc
        </value>
    </property>-->
    <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap" />
</bean>
<!--
    配置bean
    factory-bean:具体应用bean
    factory-method:调用里面的方法
-->
<bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="createFilterChainDefinitionMap" />
<bean id="filterChainDefinitionMapBuilder" class="cn.itsource.shiro.FilterChainDefinitionMapBuilder" />

5.2 准备一个构造器类

//得到Map
public class FilterChainDefinitionMapBuilder {
    public Map<String,String> createFilterChainDefinitionMap(){
        Map<String, String> map = new LinkedHashMap();
        map.put("/s/login.jsp","anon");
        map.put("/login","anon");
        //这个值之后从数据库中查询到【用户-角色-权限-资源】
        map.put("/s/permission.jsp","perms[user:*]");
        map.put("/**","authc");
        return  map;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值