{"id":24054384,"url":"https://github.com/mintoneko/springsecuritystudy","last_synced_at":"2025-02-26T10:25:42.961Z","repository":{"id":259020269,"uuid":"876122106","full_name":"mintoneko/SpringSecurityStudy","owner":"mintoneko","description":"SpringSecurity学习","archived":false,"fork":false,"pushed_at":"2024-10-22T13:14:33.000Z","size":3462,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-09T03:04:46.157Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mintoneko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-21T12:42:47.000Z","updated_at":"2024-10-22T13:14:36.000Z","dependencies_parsed_at":"2024-10-22T15:07:42.007Z","dependency_job_id":null,"html_url":"https://github.com/mintoneko/SpringSecurityStudy","commit_stats":null,"previous_names":["mobaisilent/springsecuritystudy","mintoneko/springsecuritystudy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintoneko%2FSpringSecurityStudy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintoneko%2FSpringSecurityStudy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintoneko%2FSpringSecurityStudy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintoneko%2FSpringSecurityStudy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mintoneko","download_url":"https://codeload.github.com/mintoneko/SpringSecurityStudy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240833293,"owners_count":19865099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-09T03:04:52.248Z","updated_at":"2025-02-26T10:25:42.888Z","avatar_url":"https://github.com/mintoneko.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SpringSecurityStudy\nSpringSecurity学习。\n\n跟练，跟学，这要是测试各种功能和模块。\n\n## 1.创建项目如下\n\n\u003e 也就是和之前SpringMVCDemo一样的架构，这里就不在赘述了。\n\n![image-20241021204823361](images/image-20241021204823361.png)\n\n插件的依赖如下：\n\n- spirng-webmvc\n- thymeleaf\n- fastjson2\n- fastjson2-extension-spring6\n- slf4j-api\n- slf4j-jdk14\n- lombok\n\n\u003e 不代表所有，注意后续添加，这里可以注意下，maven添加的依赖其实大多是有顺序的，有时候会因为顺序问题发生奇奇怪怪的错误。这里提醒一下。\n\n\u003e 这里在提示一下，idea有时候项目名称旁边会有一个中括号，里面和自己项目的名称不一样，其实是模块名和文件夹名冲突了而已。对应修改下组件名称即可。\n\n## 2.初始两件套\n\n\u003e config和init顾名思义，里面放置WebConfiguration和MainInitializer\n\nWebConfiguration.java\n\n```java\npackage com.mobai.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.thymeleaf.spring6.SpringTemplateEngine;\nimport org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;\nimport org.thymeleaf.spring6.view.ThymeleafViewResolver;\nimport org.thymeleaf.templateresolver.ITemplateResolver;\n\n@Configuration\n@EnableWebMvc\npublic class WebConfiguration implements WebMvcConfigurer {\n  @Bean\n  public ThymeleafViewResolver thymeleafViewResolver(SpringTemplateEngine springTemplateEngine) {\n    ThymeleafViewResolver resolver = new ThymeleafViewResolver();\n    resolver.setOrder(1);\n    resolver.setCharacterEncoding(\"UTF-8\");\n    resolver.setTemplateEngine(springTemplateEngine);\n    return resolver;\n  }\n\n  @Bean\n  public SpringResourceTemplateResolver templateResolver() {\n    SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();\n    resolver.setSuffix(\".html\");\n    resolver.setPrefix(\"classpath:\");\n    return resolver;\n  }\n\n  @Bean\n  public SpringTemplateEngine springTemplateEngine(ITemplateResolver resolver) {\n    SpringTemplateEngine engine = new SpringTemplateEngine();\n    engine.setTemplateResolver(resolver);\n    return engine;\n  }\n}\n```\n\n\u003e ThymeleafViewResolver -\u003e SpringResourceTemplateResolver -\u003e SpringTemplateEngine\n\u003e\n\u003e 尤其注意上面那个路径信息\n\nMainInitializer.java\n\n```java\npackage com.mobai.init;\n\nimport com.mobai.config.WebConfiguration;\nimport org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;\n\npublic class MainInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {\n\n  @Override\n  protected Class\u003c?\u003e[] getRootConfigClasses() {\n    return new Class[]{WebConfiguration.class};\n  }\n\n  @Override\n  protected Class\u003c?\u003e[] getServletConfigClasses() {\n    return new Class[0];\n  }\n\n  @Override\n  protected String[] getServletMappings() {\n    return new String[]{\"/\"};\n  }\n}\n```\n\n\u003e get -\u003e RootConfig -\u003e ServletConfig -\u003e Servletmappings\n\n注意这里路径和上面的路径都是/，而这次的html文件是放到resources文件夹目录下的，SpringMVCDemo是放在webapp文件夹下，都能运行是因为编译之后的结果就是直接放到根目录下。\n\n## 3.添加信息\n\n- HelloController\n- login.html\n- index.html\n\n创建基础信息，这几个省略。见SpringSecurity文档。\n\nHelloController.java\n\n```java\npackage com.mobai.controller;\n\nimport jakarta.servlet.http.HttpSession;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\n\n@Controller\npublic class HelloController {\n  //处理登录操作并跳转\n  @PostMapping(\"/login\")\n  public String login(@RequestParam String username,\n                      @RequestParam String password,\n                      HttpSession session,\n                      Model model){\n    if(\"test\".equals(username) \u0026\u0026 \"123456\".equals(password)) {\n      session.setAttribute(\"login\", true);\n      return \"redirect:/\";\n    } else {\n      model.addAttribute(\"status\", true);\n      return \"login\";\n    }\n  }\n\n  // 首页是：http://localhost:8080/mvc/,对应下面那个/请求\n  \n  //处理首页或是登录界面跳转\n  @GetMapping(\"/\")\n  public String index(HttpSession session){\n    if(session.getAttribute(\"login\") != null) {\n      return \"index\";\n    }else {\n      return \"login\";\n    }\n  }\n}\n```\n\n\u003e 这里很巧妙，注意看如何实现的。\n\n运行项目，显然出错了，如下：\n\n![image-20241021215341906](images/image-20241021215341906.png)\n\n\u003e 上次的SpringMVCDemo倒是把html放到webapp里面。\n\n这里修改好上面的WebConfiguration.java即可，改为classpath:\n\n\n\n![image-20241022104428700](images/image-20241022104428700.png)\n\n像下面遇见这种参数问题：\n\n```xml\n\u003cbuild\u003e\n    \u003cplugins\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n            \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e3.8.1\u003c/version\u003e\n            \u003cconfiguration\u003e\n                \u003ccompilerArgs\u003e\n                    \u003carg\u003e-parameters\u003c/arg\u003e\n                \u003c/compilerArgs\u003e\n            \u003c/configuration\u003e\n        \u003c/plugin\u003e\n    \u003c/plugins\u003e\n\u003c/build\u003e\n```\n\n然后clean重启服务器，不clean的话还是没用。\n\n最后登录成功结果如下；\n\n![image-20241022104617520](images/image-20241022104617520.png)\n\n注意看HelloController是怎么写的。\n\n主页和登录页修改如下；\n\nindex.html\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003ctitle\u003e白马银行 - 首页\u003c/title\u003e\n    \u003cscript src=\"https://unpkg.com/axios@1.7.7/dist/axios.min.js\"\u003e\u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cdiv\u003e\n    \u003clabel\u003e\n        转账账号：\n        \u003cinput type=\"text\" id=\"account\"/\u003e\n    \u003c/label\u003e\n    \u003cbutton onclick=\"pay()\"\u003e立即转账\u003c/button\u003e\n\u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\n\u003cscript\u003e\n    function pay() {\n        const account = document.getElementById(\"account\").value\n        axios.post('/mvc/pay', { account: account }, {\n            headers: {\n                'Content-Type': 'application/x-www-form-urlencoded',\n                'Accept': 'application/json'  // 添加Accept头\n            }\n        }).then(({data}) =\u003e {\n            console.log(data);\n            if(data.success)\n                alert(\"转账成功\")\n            else\n                alert(\"转账失败\")\n        })\n    }\n\u003c/script\u003e\n```\n\nlogin.html\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003ctitle\u003e登录白马银行\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cform action=\"login\" method=\"post\"\u003e\n  \u003clabel\u003e\n    用户名：\n    \u003cinput name=\"username\" type=\"text\"\u003e\n  \u003c/label\u003e\n  \u003clabel\u003e\n    密码：\n    \u003cinput name=\"password\" type=\"password\"\u003e\n  \u003c/label\u003e\n  \u003cbutton type=\"submit\"\u003e登录\u003c/button\u003e\n\u003c/form\u003e\n\u003cdiv th:if=\"${status}\"\u003e登录失败，用户名或密码错误！\u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n额，下面这里我一直犯406错误：\n\n![image-20241022111323852](images/image-20241022111323852.png)\n\n例如下面的HelloController，需要单独配置JSON解析器到WebConfiguration中去：\n\n```java\npackage com.mobai.controller;\n\nimport com.alibaba.fastjson2.JSONObject;\nimport jakarta.servlet.http.HttpSession;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\n@Controller\npublic class HelloController {\n\n  @ResponseBody\n  @PostMapping(\"/pay\")\n  public JSONObject pay(@RequestParam String account,\n                        HttpSession session){\n    JSONObject object = new JSONObject();\n    //登录之后才能转账\n    if(session.getAttribute(\"login\") != null) {\n      System.out.println(\"转账给\"+account+\"成功，交易已完成！\");\n      object.put(\"success\", true);\n    } else {\n      System.out.println(\"转账给\"+account+\"失败，用户未登录！\");\n      object.put(\"success\", false);\n    }\n    System.out.println(object);\n    return object;\n  }\n\n  //处理登录操作并跳转\n  @PostMapping(\"/login\")\n  public String login(@RequestParam String username,\n                      @RequestParam String password,\n                      HttpSession session,\n                      Model model) {\n    if (\"test\".equals(username) \u0026\u0026 \"123456\".equals(password)) {\n      session.setAttribute(\"login\", true);\n      return \"redirect:/\";\n    } else {\n      model.addAttribute(\"status\", true);\n      return \"login\";\n    }\n  }\n\n  //处理首页或是登录界面跳转\n  @GetMapping(\"/\")\n  public String index(HttpSession session) {\n    if (session.getAttribute(\"login\") != null) {\n      return \"index\";\n    } else {\n      return \"login\";\n    }\n  }\n}\n```\n\n有些东西，动手才能发现问题啊。\n\n## 3.添加认证界面\n\n具体省略，添加如下：\n\n![image-20241022121027402](images/image-20241022121027402.png)\n\n导入依赖：\n\n- spring-security-web\n- spring-security-config\n\n完成登陆界面。\n\n## 4.部分修改CRFS令牌\n\n![image-20241022151212518](images/image-20241022151212518.png)\n\n可见登陆逻辑处理好之后，这里的转账系统又出了点问题，403错误。\n\n\u003e 403forbidden，需要前端进行部分处理，添加部分信息给后端即可。\n\n可以关闭CSRF令牌\n\n```java\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\n\n@Configuration\n@EnableWebSecurity\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http\n            .authorizeRequests()\n                .antMatchers(\"/mvc/pay\").authenticated() // 确保 /mvc/pay 需要认证\n                .anyRequest().permitAll()\n            .and()\n            .formLogin()\n            .and()\n            .csrf().disable(); // 如果你不想处理 CSRF 令牌，可以禁用 CSRF 保护\n    }\n}\n```\n\n\u003e 修改之前的SecurityConfiguration即可，可以在这里关闭CRFS检验\n\n前端携带令牌处理：带一个不可见部分\n```html\n\u003cinput type=\"text\" th:id=\"${_csrf.getParameterName()}\" th:value=\"${_csrf.token}\" hidden\u003e\n```\n\n添加一个不可见的表单给axios处理，修改函数如下：\n\n```html\n只是简单的添加一个获取，然后给axios传递即可\n```\n\n![image-20241022183442608](images/image-20241022183442608.png)\n\n修改成功如上所示。CSRF验证是默认带的验证机制。\n\n## 5.添加加密模块\n\n\u003e 默认的加密模块是有安全隐患的，添加的加密模块如下\n\n修改之前的SecurityConfiguration.java\n\n```java\npackage com.mobai.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\n\n@Configuration\n@EnableWebSecurity   //开启WebSecurity相关功能\npublic class SecurityConfiguration {\n  //这里将BCryptPasswordEncoder直接注册为Bean，Security会自动进行选择\n  @Bean\n  public PasswordEncoder passwordEncoder() {\n    return new BCryptPasswordEncoder();\n  }\n\n  @Bean\n  public UserDetailsService userDetailsService(PasswordEncoder encoder) {\n    UserDetails user = User\n            .withUsername(\"user\")\n            .password(encoder.encode(\"user\"))   //这里将密码进行加密后存储\n            .roles(\"USER\")\n            .build();\n    System.out.println(encoder.encode(\"user\"));  //一会观察一下加密出来之后的密码长啥样\n    UserDetails admin = User\n            .withUsername(\"admin\")\n            .password(encoder.encode(\"amdin\"))   //这里将密码进行加密后存储\n            .roles(\"ADMIN\", \"USER\")\n            .build();\n    System.out.println(encoder.encode(\"admin\"));  //一会观察一下加密出来之后的密码长啥样\n    return new InMemoryUserDetailsManager(user, admin);\n  }\n}\n```\n\n\u003e 注解导入包即可\n\n加密的 密码长这样：\n\n\u003e$2a$10$aJXuq5wc/kB9tGgkKQt24./XU9iK2pMat0BrUYT3kDnSzf4PK5fIC\n\u003e$2a$10$8HTWQNOaLkI0nPLIP52Qw.hpy5zU/HJ36ZSJVl.4TuPT/ukC8ukEy\n\n现在就已经不再是明文加密了。\n\n## 6.用数据库信息校验\n\n添加如下依赖：\n\n- mybaits\n- mysql-connnector-j\n- mybaits-spring\n- spring-jdbc\n\n在SecurtiyConfiguraion中添加如下代码：\n\n\u003e 也就是注册数据库相关的Bean，本身是应该直接重新创建一个DatabaseConfiguration的\n\n```java\n  // 下面是处理数据库信息\n  @Bean\n  public DataSource dataSource() {\n    //数据源配置\n    return new PooledDataSource(\"com.mysql.cj.jdbc.Driver\",\n            \"jdbc:mysql://localhost:3306/SpringSecurityStudy\", \"root\", \"mobaisilent\");\n  }\n\n  @Bean\n  public UserDetailsService userDetailsService(DataSource dataSource,\n                                               PasswordEncoder encoder) {\n    JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);\n    //仅首次启动时创建一个新的用户用于测试，后续无需创建\n    manager.createUser(User.withUsername(\"mobai\")\n            .password(encoder.encode(\"mobai\")).roles(\"USER\").build());\n    return manager;\n  }\n  // 当然，即使放到数据库里面的密码也不是明文储存的。\n```\n\n数据库模型如下：\n\n![image-20241022190431991](images/image-20241022190431991.png)\n\n## 7.自建数据库校验\n\n项目架构如下：\n\n![image-20241022210627437](images/image-20241022210627437.png)\n\n不用多想也能知道大概应该如何添加信息了吧。\n\n\u003e 理清项目结构之后显然没有丁点难度呢。\n\n测试下能否更改密码。\n\n![image-20241022210909119](images/image-20241022210909119.png)\n\n报错了。\n\n![image-20241022210951580](images/image-20241022210951580.png)\n\n是因为把这里注释掉了，但是如果不注释的话，入屏幕所示，会有两个报错信息。\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmintoneko%2Fspringsecuritystudy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmintoneko%2Fspringsecuritystudy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmintoneko%2Fspringsecuritystudy/lists"}