springboot+shiro+md5

这里详细记录一次springboot使用shiro进行登录验证操作,同时结合MD5加密技术,实现web后台的登录功能。这里并不进行shiro认证框架的分析介绍,知识介绍一下如何使用。

:一:首先是pom.xml清单

        
			org.springframework.boot
			spring-boot-starter-jdbc
		
		
			org.springframework.boot
			spring-boot-starter-thymeleaf
		
		
			org.springframework.boot
			spring-boot-starter-web
		
		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
			1.3.2
		

		
			mysql
			mysql-connector-java
			runtime
		
		
			org.springframework.boot
			spring-boot-starter-test
			test
		

		
		
			org.apache.shiro
			shiro-core
			${shiro.version}
		

		
		
			org.apache.shiro
			shiro-spring
			${shiro.version}
		

		
		
			commons-codec
			commons-codec
		
		
			org.apache.commons
			commons-lang3
			3.6
		

二:shiro配置

@Configuration
public class ShiroConfig {

    private static String loginUrl = "/login";

    @Bean
    public UserRealm userRealm(){
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }

    /*
    配置安全管理器
     */
    @Bean
    public SecurityManager manager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager manager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(manager);
        //身份认证失败,则跳转到登录页面的配置
        bean.setLoginUrl(loginUrl);
        // Shiro连接约束配置,即过滤链的定义
        LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>();
        // 对静态资源设置匿名访问
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/bootstrap/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/font-awesome/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/layer/**", "anon");
        filterChainDefinitionMap.put("/ico/**", "anon");

        // 不需要拦截的访问
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/do_login", "anon");

        // 所有请求需要认证
        filterChainDefinitionMap.put("/**", "authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

}

这里需要注意,需要把login和do_login这两个url的拦截给忽略掉,否则会被拦截,无法进行登录操作。

3:编写realm模块,继承自AuthorizingRealm类并重写其中的两个方法doGetAuthorizationInfo和doGetAuthenticationInfo两个方法,前者为权限管理处理方法,后者是处理身份认证的处理方法,也就是我们这次的重点,权限处理暂时不处理。

public class UserRealm extends AuthorizingRealm{

    @Autowired
    LoginService loginService;

    /*
    处理权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        return null;
    }

    /*
    处理认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();
        String password = "";
        if (token1.getPassword() != null){
            password = new String(token1.getPassword());
        }
        User user = null;
        System.out.println("用户名"+username+"密码"+password);
        user = loginService.login(username,password);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,password,getName());
        return info;
    }
}

注意SimpleAuthenticationInfo类我们并没有把salt给上去,这里的密码加解密由我们自己是实现。

4:编写LoginController处理前端的登录操作

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String loginPage(){
        System.out.println("访问page");
        return "login";
    }

    //ajax执行登录操作
    @RequestMapping(value = "/do_login",method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult login(String username, String password, HttpSession session){
        System.out.println("访问lgon");
        //再进行一遍MD5加密
        String realPassword = MD5Utils.formPassToDbPass(password);
        UsernamePasswordToken token = new UsernamePasswordToken(username,realPassword);
        Subject subject = SecurityUtils.getSubject();
        try{
            subject.login(token);
            session.setAttribute("user", subject.getPrincipal());
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("do_login"+" "+AjaxResult.success("登陆成功"));
        return AjaxResult.success("登录成功");
    }

    @RequestMapping("/home")
    public String index(){
        return "index";
    }
}

在login方法中,我们拿到的password是前端用户输完密码后的一次md5加密后的密码,前端加密下边会讲到,我们拿到这个password后再进行一边加密操作,然后生成token,交给subject去进行登录操作,最后返回我们封装好的AjaxResult,返回到前端为json类型,MD5Utils类如下:

public class MD5Utils {
    private static final String SALT = "1a2b3c4d";

    private static String md5(String pass){
        return DigestUtils.md5Hex(pass);
    }

    //表单到后台的加密
    public static String inputPassToFormPass(String inputPass){
        String saltPass = "" + SALT.charAt(0) + SALT.charAt(2) + inputPass + SALT.charAt(5) + SALT.charAt(4);
        return md5(saltPass);
    }

    //后台到数据库的加密
    public static String formPassToDbPass(String formPass){
        String saltPass = "" + SALT.charAt(0) + SALT.charAt(2) + formPass + SALT.charAt(5) + SALT.charAt(4);
        return saltPass;
    }

    //综合两种加密
    public static String inputPassToDbPass(String inputPass){
        String realPass = formPassToDbPass(inputPassToFormPass(inputPass));
        return realPass;
    }

    public static void main(String[] args) {
        String realPass = inputPassToDbPass("1234");
        System.out.println(realPass);
    }
}

这里的盐我们写死在这里,实际项目中用该不会这么做,数据库中的密码也是我们提前用这个工具类手动生成的,这步可以写成一个注册的操作。

5:前端页面login.html的编写,需要注意的是,我们取消了form表单的submit提交功能,交由onclick的login()方法去处理。

login方法如下,拿到用户输入的密码,进行一次md5加密,然后使用ajax向后台请求。若返回结果成功,则进行页面跳转。

var salt = "1a2b3c4d";
function showLoading() {
    var idx = layer.msg('处理中...', {icon: 16,shade: [0.5, '#f5f5f5'],scrollbar: false,offset: '0px', time:100000}) ;
    return idx;
}

function login() {
    showLoading();
    var inputPass = $("#password").val();
    var username = $("#username").val();
    if (inputPass.length == 0 || username.length == 0){
        alert("用户名或密码不允许为空");
        layer.closeAll();
    }else{
        var str = salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
        var password = md5(str);
        $.ajax({
            url:"/do_login",
            type:"post",
            data:{
                username:username,
                password:password
            },
            success:function (datas) {
                layer.closeAll();
                //根据返回的码判断结果
                console.log(datas);
                if(datas.code == 1){
                    layer.msg("登录成功");
                    window.location.href="/home";
                }else{
                    layer.msg(datas.msg);
                }
            }
        })
    }

}

6:验证

当你没有进行登录的时候,进入任何界面都会先跳转到登录界面,登录完成后跳转到指定页面。

7:整个demo这里是下载链接,欢迎大家下载并指正。

https://download.csdn.net/download/fly_rice/10557890

你可能感兴趣的:(springboot,shiro,md5,登录)