Shiro学习(1)用户认证

主要学习参考:http://jinnianshilongnian.iteye.com/blog/2018936

前言

1、shiro是apache的一个开源框架,是一个权限管理的框架,可以实现用户认证、用户授权,当然还有其它一些功能。

2、用户认证就是看能不能登录?在用户登录之后,首先会给不同的用户分配不同的角色,然后给不同的角色授权不同的资源,结果不同的用户也就有了不同的权限,能访问的资源就不一样

1、Shiro的API

Shiro的对外API核心就是Subject;其每个API的含义:

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

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

也就是说对于我们而言,最简单的一个Shiro应用:

1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;

2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

从以上也可以看出,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。

2、身份验证的原理

(1)凭借什么进行验证:

在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份:

principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。

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

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

(2)身份验证的步骤:

1、收集用户身份/凭证,即如用户名/密码;

2、调用Subject.login进行登录,如果失败将得到相应的AuthenticationException异常,根据异常提示用户错误信息;否则登录成功;

3、登录成功,跳转到主页。

实现上述步骤的代码写在controller层:接收浏览器提交的userName和passWord参数,再进行验证

@RequestMapping("/Login")
public String Login(User user,HttpSession session) {
	Subject subject = SecurityUtils.getSubject();
		try {
			//用token保存输入的账号和密码
			UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassWord());
			//进行用户验证
			subject.login(token);
		} catch (AuthenticationException e) {
			e.printStackTrace();
		}
	return "index.html";
}

(3)上述代码实际的验证过程在Shiro内部的流程:

(4)上面的流程就是SecurityManager给Authenticator一个token值,让它去进行身份验证,Authenticator又没有数据库中的账号和密码,Realm就是数据源,自定义Realm就是为了获取数据,而Realm在配置文件中会注入到SecurityManager中,SecurityManager就能把数据源给Authenticator进行身份验证。

Realm身份验证代码,自定义UserRealm.java中身份验证的代码:

public class UserRealm extends AuthorizingRealm {
	@Autowired
	private UserService userService;
	//认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //从token获得输入的账号
		String userName = token.getPrincipal()+"";
        //根据输入的账号到数据库去查找对应的用户
		User user = userService.findUserByUserName(userName);
        //用户不存在,表明账号不存在,则登录失败
		if(user==null){
			System.out.println("账号不存在");
			throw new UnknownAccountException();
		}else{
            //否则表明账号存在,判断密码是否正确
            /*注册用户时,我们若对密码进行先添加salt盐值后通过MD5加密,最后保存到数据库
             *那么在登录时,就需要根据当前输入的密码结合从数据库中取出的user的salt值,再经过
             *1024次MD5加密得到的字符串和user的密码进行对比,若相同才代表密码正确
             */
            //获得user的salt值
			ByteSource salt = ByteSource.Util.bytes(user.getSalt());
          
			//下面一句的作用是先比较账号,肯定相同;然后比较密码,相同则返回authenticationInfo,不同则抛异常 
            //如果验证成功,最终这里返回的信息authenticationInfo 的值与传入的第一个字段的值相同,这里就是账号
			SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(),user.getPassWord(),salt,getName());
            
			return authenticationInfo;
		}
	}
}

别人对上面authenticationInfo的理解:https://blog.csdn.net/qq_35981283/article/details/78634575

3、shiro的配置文件

spring-shiro.xml:

<!-- 配置自定义Realm -->
<!-- 通过Realm获取账号,密码,权限码,角色码 -->
<bean id="myRealm" class="shiro.UserRealm">
    
    <property name="credentialsMatcher" >
        <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <!-- 加密方式和加密次数 -->
            <property name="hashAlgorithmName" value="MD5"></property>
            <property name="hashIterations" value="1024"></property>
        </bean>
    </property>
</bean>

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

<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

<!-- 开启Shiro注解 -->
<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>
  
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
    <property name="exceptionMappings">  
        <props>  
            <prop key="org.apache.shiro.authz.UnauthorizedException">
                /unauthorized
            </prop>  
        </props>  
    </property>  
</bean>

<!-- Shiro过滤器 核心-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	<!-- Shiro的核心安全接口,这个属性是必须的 -->
	<property name="securityManager" ref="securityManager"/>
	<!-- 身份认证失败,则跳转到登录页面的配置 -->
	<property name="loginUrl" value="/login.html"/>
	<property name="successUrl" value="/index.jsp"/>
	<!-- 权限认证失败,则跳转到指定页面 -->
	<property name="unauthorizedUrl" value="/login.html"/>
	<!-- Shiro连接约束配置,即过滤链的定义 -->
	<property name="filterChainDefinitions">
		<value>
			<!-- /candidate/admin/**=authc -->
			<!--anon 表示匿名访问,不需要认证以及授权-->
			/login.html = anon
			/user/login.do = anon
			/sockjs/** = anon
			/static/** = anon
			/code.htmls = anon
			/loginIn.htmls = anon
			/candidate/** = anon
			/websocket/** = anon
			/logout = logout
			<!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
			/**=authc
        </value>
	</property>
</bean>

4、配置文件写好了,如何让工程启动时能加载这个配置文件呢?

方法1,在web.xml中配置:

  <!--加载 Spring和mybatis和shiro的配置文件 -->  
    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>classpath:spring-mybatis.xml,classpath:spring.xml,classpath:spring-shiro</param-value>  
    </context-param> 


方法2,在spring中引入spring-shiro.xml:

<import resource="spring-shiro.xml"/>

注意在spring-mvc中添加:

    <!-- 防止注解无效 -->
	<tx:annotation-driven/>
	<!-- 基于类的代理被创建 -->
     <aop:config proxy-target-class="true" />

还需要在web.xml中配置Shiro的过滤器,目的是让所有的url请求,先经过这个过滤器进行过滤:

  <!-- shiro过滤器定义,让所有的url请求都经过shiro过滤器 -->
	<filter>
	    <filter-name>shiroFilter</filter-name>
	    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	    <init-param>
	        <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
	        <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> 

下一篇:学习用户授权

https://blog.csdn.net/Carl_changxin/article/details/82049151

 

猜你喜欢

转载自blog.csdn.net/Carl_changxin/article/details/81989698