发现问题:
我们在写一个网站的时候会遇到有的页面不登录就可以访问而有的页面必须要登录才可以访问,或者有的页面必须要具有某个权限才可以访问,再就是用户的数据都是存储在数据库里,我们如何对用户的密码更好的保护呢?
我们发现shiro可以很好地解决这些问题,下面我们来看一下他是如何解决的
样例演示
- 添加pom依赖
<!--ssm整合shiro-->
<!--======================================shrio=================================================-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.2.4</version>
</dependency>
- 在web.xml中配置shiro过滤器
<!--===============================================shiro过虑器================================================-->
<!-- shiro过虑器,DelegatingFilterProx会从spring容器中找shiroFilter代理模式(律师模式) -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!--设置为true有servlet容器控制filter声明周期-->
<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>
4配置spring的配置文件
<!-- Shiro 的Web过滤器 -->
<!--1、与web.xml对应的bean-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 如果没有认证将要跳转的登陆地址,http可访问的url,如果不在表单认证过虑器FormAuthenticationFilter中指定此地址就为身份认证地址 -->
<property name="loginUrl" value="/login" />
<!-- 没有权限跳转的地址 -->
<property name="unauthorizedUrl" value="/role" />
<!--过滤定义,从上而下,蒋匿名的anon放最下面-->
<property name="filterChainDefinitions">
<value>
/Main=authc
/addmember = authc
/costmoney = authc
/selectdate =roles["高级"]
/selectmember = authc
/selectAllMembers=roles["高级"]
/categrymanager=authc
/productmanager=authc
/ordermanager=authc
/selectpopcategry=authc
</value>
</property>
</bean>
<!-- 2、安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
</bean>
<!--3、realm-->
<!--<bean id="userRealm" class="utils.UserRealm"/>-->
<bean id="userRealm" class="utils.UserRealm">
<!-- 配置密码匹配器 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密算法为MD5 -->
<property name="hashAlgorithmName" value="MD5"></property>
<!-- 加密次数 -->
<property name="hashIterations" value="3"></property>
</bean>
</property>
</bean>
好了现在我们可以写代码了:
首先,我们先完成登录和注册功能:
注册时候我们如何将用户的密码加密我们只需要在service中编写加密逻辑即可
public int add(InsertMember insertMember) {
//定义一个盐值,这里我们用的用户名作为盐值
ByteSource salt = ByteSource.Util.bytes(insertMember.getUsername());
int hashIterations = 3;//加密3次
//加密方式,需要加密的密码,盐值,次数
SimpleHash hash = new SimpleHash("MD5",insertMember.getPassword(),salt,hashIterations);
//hash.toString()即为加密后的密码,我们用它覆盖传入的用户输入的密码
insertMember.setPassword(hash.toString());
hash.toString()即为加密之后的密码。
那么登录功能该如何实现呢?
因为我们的密码匹配器是这样配置的所以我们在注册加密的时候方式必须为MD5,次数为3,否则无法匹配,我们来看一下controller中
@RequestMapping("/Login1")
public String getMain( HttpSession session,String username, String password) {
Subject subject=SecurityUtils.getSubject();
//认证提交认证token
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
try {
subject.login(token);
}catch (Exception e){
//如果账号密码错误会出现异常
return "fail";
}
return "Main";
}
之后我们需要写一个Realm来对应密码匹配器中的class
该类需要继承AuthorizingRealm然后重写认证方法
//用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username=(String)authenticationToken.getPrincipal();
InsertMember insertMember= insertMemberDao.findByUsername(username);
if(insertMember.getPassword()==null){
return null;
}
//使用账号作为盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
//构造器参数(用户输入的用户名,用户输入的密码,盐值,this.getName())
System.out.println(this.getName());
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(insertMember.getUsername(),insertMember.getPassword(),credentialsSalt,this.getName());
return info;
}
这样登录功能就实现了。
然后我们来实现未登录拦截功能和不具备权限无法访问功能:
只需在spring配置文件里用url=authc代表需要登录才可以访问,url=anno代表没有权限限制,url=roles[“xx”]代表需要具有xx权限才可以访问该路径,有人会问那么如果没有登录或者没有权限会有什么效果?
如果我没有权限或者没有登录就会访问spring里配置的url。
最后说一下退出登录,如何退出登录
@RequestMapping("loginout")
public String LoginOut(){
Subject subject=SecurityUtils.getSubject();
subject.logout();
return "Login";
}
这样就会就会退出登录了,需要用subject.logout()方法取消认证。
总结:
Shiro框架让我们用起来很方便,可以帮助我们加密用户密码,增加安全性,还可以让我们更好的管理网站的认证和权限管理操作
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}