发表于: 2017-08-17 17:35:30

1 1130


今天学习了如何用shiro实现登陆验证。shiro是一个十分强大的权限管理系统,和Spring和JavaWeb工程有很好的整合,所以对于一个Spring MVC项目来说,是十分理想的选择,尤其是当有许多角色需要管理时,自己去写拦截器就变得很复杂。


shiro主要可以解决验证和授权的问题,登陆就是一个验证工作,需要验证登陆的用户名和密码是否正确。


密码不管储存在什么地方,都是以暗文形式储存,即必须加过密。


shiro自带多种加密方式,例如md2,md5,sha256等,还支持加盐,加盐方式可以把随机生成的盐自定义在数据库的另一列,加强安全性。


shiro支持各种各样的储存敏感信息的方式,对于少量的用户,完全可以将用户名和密码token储存在shiro配置文件中,配置文件也可以放在远程服务器。


shiro还支持安全的使用缓存。


shiro对于敏感信息的读取,有一个自己的类叫做Realm,shiro的Realm类可以看做shiro自己的DAO,shiro为了确保安全,使用自己的Realm读取敏感信息,所以如果使用数据库储存敏感信息,必须自己实现Realm类才能使用shiro。


自己实现shiro的Realm类,可以简单的使用原生jdbc,配置单独的数据源,不需要整合dao框架。


shiro的配置有多种方式,默认通过shiro.ini文件进行全局配置,但也可以与Spring进行整合,也可以直接在web.xml文件中进行配置,但今天是第一次进行配置,所以还是选择了默认的shiro.ini文件。


shiro与Spring整合有一个不可替代的好处,就是可以直接使用注解对方法添加权限,这是普通情况下使用URL路径进行配置无法实现的,所以将来对shiro和Spring进行整合还是十分必要的。


使用shiro框架后,不需要自己配置Cookie和session,完全有shiro自己实现,默认使用的就是Web容器的Session,也可以自定义Session。


在Spring MVC项目中实现登陆,只需要配置shiro.ini,和Realm实现类,和web.xml中的一个监听器和过滤器,具体如下。


shiro.ini

[main]
myRealm = com.ptteng.carrot.yongzheng.util.AuthenticateRealm
securityManager.realm = $myRealm
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
sha256Matcher.storedCredentialsHexEncoded = false
myRealm.credentialsMatcher = $sha256Matcher
authc.loginUrl = /login.jsp
[urls]
/login.jsp = authc
/a/** = authc


web.xml

<!--shiro过滤器-->
<listener>
   <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
   <filter-name>ShiroFilter</filter-name>
   <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>ShiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
   <dispatcher>INCLUDE</dispatcher>
   <dispatcher>ERROR</dispatcher>
</filter-mapping>


Realm实现类,配一个数据源(不能使用Autowire,原因可能是shiro的初始化更靠前):

public class AuthenticateRealm extends AuthenticatingRealm {

private static final Log log = LogFactory.getLog(AuthenticateRealm.class);

   protected static final String AUTHENTICATION_QUERY = "SELECT password_token FROM account WHERE name = ?";

   private DataSource dataSource;

   public AuthenticateRealm() {
       BasicDataSource basicDataSource = new BasicDataSource();
       basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
       basicDataSource.setUrl("jdbc:mysql://zengtian.cc:3306/carrot_yongzheng");
       basicDataSource.setUsername("root");
       basicDataSource.setPassword("root");
       dataSource = basicDataSource;
   }

@Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
       UsernamePasswordToken userToken = (UsernamePasswordToken) token;
       String username = userToken.getUsername();
       // Null username is invalid
       if (username == null) {
           throw new AccountException("Null usernames are not allowed by this realm.");
       }
       Connection conn = null;
       SimpleAuthenticationInfo info = null;
       try {
           conn = dataSource.getConnection();
           PreparedStatement ps = null;
           ps = conn.prepareStatement(AUTHENTICATION_QUERY);
           ps.setString(1, username);
           ResultSet rs = null;
           String password = null;
           rs = ps.executeQuery();
           while (rs.next()) {
           password = rs.getString(1);
           }
           if (password == null) {
             throw new UnknownAccountException("No account found for user [" + username + "]");
           }
           info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());

       } catch (SQLException e) {
           final String message = "There was a SQL error while authenticating user [" + username + "]";
           log.error(message, e);
           // Rethrow any SQL errors as an authentication exception
           throw new AuthenticationException(message, e);
       } finally {
              JdbcUtils.closeConnection(conn);
       }
       return info;
   }

//禁用shiro服务
   /*@Override
   public boolean supports(AuthenticationToken token) {
       return false;
   }*/
}

加密帮助类,用于做注册页面时使用,加密方式一定要和shiro.ini中一致,否则注册的加密和登陆的加密不一样:

public class Hasher{

public static void main(String[] args) {
       Hasher hasher = new Hasher();
       System.out.println(hasher.encrypt("admin"));
   }

public String encrypt(String input){
       //加盐
       //RandomNumberGenerator rng = new SecureRandomNumberGenerator();
       //Object salt = rng.nextBytes();
       //String out = new Sha256Hash(input, salt, 1024).toBase64();

       return new Sha256Hash(input).toBase64();
   }
}

问题:登陆成功后,会自动跳转到项目根路径,找不到地方改,不能指定成功页面,除非复写过滤器的方法。


明天:解决登陆中的种种问题。


总结:无


进度:http://task.ptteng.com/zentao/project-burn-277.html

demo延期至少一周。



返回列表 返回列表
评论

    分享到