主要学习参考: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