Spring Securityは、Springが提供するセキュリティコンポーネントであり、主にプロジェクト内のユーザーのIDを識別および認証するために使用されます。
SpringセキュリティフレームワークはSpring-Securityであり、現在のプロジェクトのユーザーログインとログイン後の権限管理を管理する機能であり、Springフレームワークが提供する権限管理とセキュリティソリューションです。
Spring-Securityフレームワークと同様の機能を持つフレームワークはShiroです
Spring Securityを使用する前に、依存関係を追加する必要があります。依存関係は、SpringBootプロジェクトの作成時に直接確認できます。または、作成済みのプロジェクトに追加することもできます。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
依存関係を追加した後、サービスを開始すると、ランダムに生成されたパスワードの文字列が表示されます。これを使用して、Spring-Securityシステムにログインできます。
ユーザー名:ユーザーパスワードは、サービスの開始時に生成される文字列です。
この依存関係が読み込まれたら、最初にSpring-Securityにログインして、現在のプロジェクトのリソースにアクセスする必要があります。
ユーザー名とパスワードをカスタマイズしたい場合
次に、application.propertiesファイルで指定する必要があります
コードは以下のように表示されます
spring.security.user.name=admin
spring.security.user.password=666666
上記の構成では、サービスの開始時にランダムなパスワードは生成されず、構成されたユーザー名とパスワードでログインできます。
実際の開発では、パスワードをプレーンテキストで保存することはできません。プレーンテキストのパスワードは、セキュリティを向上させるために、特定の暗号化アルゴリズムに従って暗号文パスワードに暗号化できます。現在、一般的な暗号化アルゴリズムには、md5、Bcryptなどがあります。
私たちのプロジェクトでは、Spring Securityに付属のBcrypt暗号化を使用しています。Bcryptを使用してプレーンテキストのパスワードを暗号化および検証する操作を実装しましょう。
まず、暗号化されたオブジェクトをSpringコンテナに挿入し、プロジェクトにセキュリティパッケージを作成し、パッケージにSecurityConfigクラスを作成します。
// @Configuration表示当前这个类也是Spring的配置类
// Spring扫描到这类时,就会把它当做配置类解析
@Configuration
public class SecurityConfig {
//向spring容器中注入一个加密对象,用于对密码加密
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
テスト:
@Autowired
PasswordEncoder passwordEncoder;
//加密
@Test
public void encode(){
String pwd=passwordEncoder.encode("666666");
System.out.println(pwd);
//$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq
}
//验证
@Test
public void decode(){
boolean bool=passwordEncoder.matches("666666",
"$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq");
System.out.println(bool);
}
プロジェクトがPasswordEncoderタイプのオブジェクトを挿入すると、SpringSecurityフレームワークはこのオブジェクトを自動的に使用して現在のプレーンテキストのパスワードを暗号化し、application.propertiesファイル内のユーザーのパスワードを暗号化されたものに変更する必要があります。
application.propertiesログイン構成は次のように変更されます
spring.security.user.name=admin
spring.security.user.password=$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq
パスワードの暗号化が必要な場合、PasswordEncoderオブジェクトの挿入を構成クラスに追加する必要があります。これは非常に面倒です。
暗号文パスワードに特定のアルゴリズムIDを追加すると、SpringSecurityは暗号化アルゴリズムに従って自動的に暗号化します。これはより簡単です。
具体的な方法は次のとおりです。application.propertiesの変更
spring.security.user.name=admin
spring.security.user.password={bcrypt}$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq
このようにして、SecurityConfigクラスに挿入されたPasswordEncoderに注釈を付けたり削除したりできます
@Configuration
public class SecurityConfig {
//向spring容器中注入一个加密对象,用于对密码加密
/*@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}*/
}
プロジェクトには多くのユーザーがいて、それらはすべてデータベースに保存されています。構成ファイルの構成ではログインできないため、Javaコードでログインを確認する方法を学ぶ必要があります。この一連の確認操作はJava構成クラスで記述する必要があります
上記の章で作成したSecurityConfigを使用するだけです!!!
コード例:
@Configuration
//下面的注解表示开启Spring-Security的权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//配置登录验证(即用户名和密码的验证)
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("tom")
.password("{bcrypt}$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq")
//上面的配置是规定了用户的用户名和密码,可以使用他们登录
//下面的配置是规定了这个用户的特定权限
//有了这个特定权限才可以访问特定的方法
.authorities("/user/get");
}
}
上記のコードでは、tomと正しいパスワードを使用して一般的なリソースにアクセスできますが、特別な権限を持つリソースにアクセスできない場合は、前に作成したUserControllerクラスのメソッドを書き直します。
リクエストパスを設計するときは、{}を使用してリクエストパスの名前をフレームに入れ、変数を表すことができます。後でクライアントがリクエストを送信すると、{}プレースホルダーに対応する場所は任意のデータになります。{}プレースホルダーがリクエストパスで使用されている場合、リクエストを処理するメソッドのパラメーターリストで、パラメーター宣言の前に@PathVariableアノテーションを追加して、プレースホルダーの値を取得します。RESTFULスタイルのAPIであるURLにコアパラメーターを配置します。
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private IUserService userService;
// http://localhost:8080/test/user/1
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Integer id) {
return userService.getById(id);
}
}
あなたは上記のURLへのアクセスを制限する必要がある場合は、例えば、一部のユーザーがアクセスすることができますが、いくつかの他のユーザーがアクセスすることはできません、次のような、自分で「認証文字列」を設計することができ"a"
たりなど!一般的な使用などのアクセス権限、定義するためにURLのスタイルを使用することが推奨されるかを。"hello"
"test:user:info"
"/user/user/info"
@GetMapping("/user/{id}")
@PreAuthorize("hasAuthority('test:user:info')")
public User getUserById(@PathVariable("id") Integer id) {
return userService.getById(id);
}
注:権限文字列のデザインは、URLのデザインとは何の関係もありません。
リクエスト@PreAuthorize
を処理するメソッドの前に、「リクエストされたパスにアクセスするには特定の権限が必要」と宣言するアノテーションを設定できます。次に例を示します。
コード例:
//实际访问路径为:localhost:8080/v1/users/get?id=1
@GetMapping("/get")
@PreAuthorize("hasAuthority('/user/get')")//设置访问这个方法的特殊权限
public User get(Integer id){
User u=userService.getById(id);
return u;
}
@GetMapping("/list")
@PreAuthorize("hasAuthority('/user/list')")
public List<User> list(){
List<User> list=userService.list();
return list;
}
上記の注釈構成について:
アノテーション名@PreAuthorizeは、「リクエストを処理する前に権限を確認する」ことを意味します。
注釈属性のhasAuthorityは、「特定の権限が必要」を意味します。
アノテーション属性の/ user / listは、単なる識別であるカスタム権限文字列です。
ユーザーログイン-UserDetailsServiceインターフェースUserDetailsServiceを使用して認証データを提供します
Spring SecurityはUserDetailsService
インターフェースを定義し、インターフェースには抽象的なメソッドがあります
UserDetailsServiceは、Spring Securityによって提供されるインターフェイスです。このインターフェイスで定義されたメソッドは、タイプUserDetailsのオブジェクトを返します。このオブジェクトには、ユーザー、ユーザー名\パスワード\権限などに関するさまざまな情報が含まれます。
このインターフェイスを実装するクラスを記述しますUserDetailsServiceImplコードは次のとおりです。
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
このメソッドの機能は次のとおりです。ユーザー名を指定して、ユーザーの詳細情報(返却する必要があるUserDetails
タイプのオブジェクト)をした後。春のセキュリティは、ユーザーの詳細情報を取得し、それが自動的にユーザーの本人確認を完了します、後にユーザ権限情報を含みます検証は成功します。フレームワークが扱うことは、開発者として、「ユーザー名に基づいてユーザーの詳細を取得する」という問題を解決するだけです。
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String name)
throws UsernameNotFoundException {
UserDetails user=null;
//判断用户是不是jerry
if("jerry".equals(name)){
//设置jerry用户的详情
user= User.builder()
.username("jerry")
.password("{bcrypt}$2a$10$ytxmGeWcRZObqoDmlhnWxe6KqUjb9DTONmQVKkmwneHQtZw4LQtiq")
.authorities("/user/get")
.build();
}
return user;
}
}
注:上記のクラスは、コンポーネントによってスキャンされ、@Component
注釈が付けられたパッケージに含まれている必要があります。そうすると、Springフレームワークが上記のクラスのオブジェクトを自動的に作成および管理し、このクラスのオブジェクトを直接アセンブルできます。
次に、SecurityConfig
クラスに戻り、上記のクラスのオブジェクトを適用します。
次に、SecurityConfigクラスの宣言の前に@EnableGlobalMethodSecurity(prePostEnabled = true)アノテーションを追加して、アクセス許可チェックを許可する必要があります。例えば:
@Configuration
//下面的注解表示开启Spring-Security的权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired(required = false)
UserDetailsServiceImpl userDetailsService;
//配置登录验证(即用户名和密码的验证)
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService);
}
}
厳密に言えば、上記の方法は「ログイン」方法ではなく、「ユーザー詳細を取得する」方法であり、ログインが成功したかどうかさえわからないため、パラメータリストにパスワードがありません。将来的には、Spring Securityは上記のメソッドによって返されるオブジェクトを取得し、パスワードが正しいことなどを確認します。
Spring-Securityは接続クエリを使用してユーザー権限を取得します
ユーザーの詳細を照会するには、2つの方法があります。1つは、ユーザー名に基づいてユーザー情報を照会する方法と、上記のユーザーIDに基づいてアクセス許可を照会して、ログインに必要なすべての情報を取得する方法です。
UserMapperインターフェースの例では:
@Repository
public interface UserMapper extends BaseMapper<User> {
// 根据用户的id查询用户的所有权限
@Select("SELECT p.id,p.name" +
"FROM user u" +
"LEFT JOIN user_role ur ON u.id=ur.user_id" +
"LEFT JOIN role r ON r.id=ur.role_id" +
"LEFT JOIN role_permission rp ON r.id=rp.role_id" +
"LEFT JOIN permission p ON p.id=rp.permission_id" +
"WHERE u.id=#{id}")
List<Permission> findUserPermissionById(Integer id);
//按用户名查询用户
@Select("select * from user where username=#{username}")
User findUserByUsername(String username);
}
作成されたプログラムの基本原則は、独自のサービスレイヤーによって独自に作成されたマッパーを呼び出すことです。この呼び出しは非常に特殊です。サービスを呼び出すのはコントローラーではなく、SpringSecurityです。最初にIUserServiceインターフェイスでメソッドを宣言します。
public interface IUserService extends IService<User> {
//根据用户名获得用户认证信息的业务逻辑层方法
UserDetails getUserDetails(String username);
}
次に、実装クラスUserServiceImplに実装します。
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails getUserDetails(String username) {
//根据用户名查询出用户对象
User user=userMapper.findUserByUsername(username);
// 如果用户为空,表示用户名不存在,返回登录失败
if(user==null){
return null;
}
//根据用户id查询用户权限
List<Permission> ps=userMapper
.findUserPermissionById(user.getId());
//将查询到的所有权限名称填装到一个数组中
String[] auths=new String[ps.size()];
int i=0;
for(Permission p: ps){
auths[i++]=p.getName();
}
//构建UserDetails
UserDetails u= org.springframework.security.core
.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.authorities(auths)
//getLocked默认都是0,所以要判==1得到false表示不锁定
.accountLocked(user.getLocked()==1)
//getEnabled默认都是1,所以要判==0得到false表示可用
.disabled(user.getEnabled()==0)
.build();
return u;//一定不要返回null!!!!
}
}
最後に、UserDetailsServiceImplクラスのコード例をリファクタリングします。
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private IUserService userService;
@Override
public UserDetails loadUserByUsername(String name)
throws UsernameNotFoundException {
UserDetails user=userService.getUserDetails(name);
return user;
}
}
ユーザーログイン-アクセス制御について(インターセプターと同等)
承認スコープを制御し、ログインページの承認スコープコントロールをカスタマイズします
実際、アクセスするためにWebサイトのすべてのページリソースにログインする必要はないため、Spring Securityの制限戦略は比較的厳格です。これらの認証範囲を自分で設定する場合は、次のコードが必要です。メソッドコードをに追加します。 SecurityConfigクラスは次のとおりです
でSecurityConfig
書き換えprotected void configure(HttpSecurity http)
方法:
/设置SpringSecurity的授权范围和登录页面
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //关闭防跨域攻击
.authorizeRequests()//开始设置授权范围
.antMatchers(
"/index.html",
"/img/*",
"/js/*",
"/css/*",
"/bower_components/**",
"/login.html"
).permitAll() //上面路径允许直接访问
.anyRequest().authenticated()//其他的资源需要登录
.and().formLogin()//登录方式是表单
.loginPage("/login.html")//指定登录的页面
.loginProcessingUrl("/login")//当登录页面提交时,会提交给哪个路径
.failureUrl("/login.html?error")//登录失败从新登录,显示错误提示
.defaultSuccessUrl("/index.html")//登录成功跳转到index.html
.and().logout() //配置登出
.logoutUrl("/logout")//设置登出路径
//登出成功跳转登录页面,并提示已登出
.logoutSuccessUrl("/login.html?logout");
}
// 准备白名单,是不需要登录就可以访问的路径
// 授权设置,是相对固定的配置
// csrf().disable() > 关闭跨域攻击
// authorizeRequests() > 对请求进行授权
// antMatchers() > 配置访问白名单
// permitAll() > 对白名单中的路径进行授权
// anyRequest() > 其它的请求
// authenticated() > 仅经过授权的允许访问,也可以理解为“未被授权将不允许访问”
// and.formLogin() > 未被授权的将通过登录表单进行验证登录并授权
- パラメータオブジェクト
http
を呼び出すchainメソッドの構成は比較的固定されているか、理解してみるか、直接適用することができます。 -
上記の呼び出しは
antMatchers( )
、SpringMVCインターセプターを使用する場合のホワイトリストの構成と同等です。メソッドパラメーターで、直接解放する必要のあるすべてのパス(ログインせずにアクセスできる場所)を追加する必要があります。次に例を示します。@Override protected void configure(HttpSecurity http) throws Exception { // 准备白名单,是不需要登录就可以访问的路径 // String[] antMatchers = { // "/index.html" //}; String[] antMatchers = { "/index.html", "/bower_components/**", "/css/**", "/img/**", "/js/**" }; http.csrf().disable() .authorizeRequests() .antMatchers(antMatchers).permitAll() .anyRequest().authenticated() .and().formLogin(); }
ユーザーログイン-カスタムログインページを置き換えます
まず、Thymeleaf依存関係をプロジェクトに追加します。
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
カスタムログインページはHTMLテンプレートページとして設計されます。ログインURLが要求されると、HTMLテンプレートページに転送され、テンプレートフォルダがプロジェクトのsrc / main / resouecesの下に作成されます。これはによって使用されます。デフォルトのSpringBootプロジェクトテンプレートページフォルダを設定する必要はありません。転送時に、HTMLテンプレートファイルがデフォルトでこのフォルダに照会されます。フォルダが作成されたら、静的フォルダのlogin.htmlファイルをにドラッグします。テンプレートフォルダ。
次に、コントローラーをカスタマイズし、ログインページのリクエストパスを設計します。パスのリクエストを処理すると、/ templates /login.htmlファイルに直接転送されます。Thymeleafは統合中に/ templates /のプレフィックスをすでに構成しているためです。 、サフィックスは次のとおりです。構成は.htmlであるため、コントローラーに返されるビュー名はloginです。
コントロールレイヤーに新しいコントローラークラスを作成して、SystemControllerという名前のlogin.htmlページを表示します。コードは次のとおりです。
@RestController
public class SystemController {
@GetMapping("/login.html")
public ModelAndView loginForm(){
return new ModelAndView("login");
}
}
@Controller
public class SystemController {
@GetMapping("/login.html")
public String login() {
return "login";
}
// 适用于使用@RestController时
// public ModelAndView login() {
// return new ModelAndView("login");
// }
}